fix: FAB 在切换页面时文字溢出

This commit is contained in:
Super12138 2025-11-09 10:10:30 +08:00
parent 0fb4192493
commit 7fa618a611
5 changed files with 55 additions and 96 deletions

View file

@ -37,7 +37,7 @@ android {
applicationId = "cn.super12138.todo"
minSdk = 24
targetSdk = 36
versionCode = 791
versionCode = 883
versionName = "2.3.3"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

View file

@ -1,34 +1,29 @@
package cn.super12138.todo.ui.components
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.FloatingActionButton
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FloatingActionButtonDefaults
import androidx.compose.material3.FloatingActionButtonElevation
import androidx.compose.material3.Icon
import androidx.compose.material3.SmallExtendedFloatingActionButton
import androidx.compose.material3.Text
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import cn.super12138.todo.utils.VibrationUtils
/**
* 带动画且比 Material 3 内置组件动画好看的的可扩展 FAB
* * 内置组件的动画总是卡一下
* 封装的内置组件 FAB在点击时支持添加震动反馈
* * 现在内置组件的动画好像好一点了
*
* 将缩放部分转为最简单的`AnimatedVisibility`实现
* @param icon FAB 的前置图标
* @param text FAB 的文本
* @param textOverflow FAB 文本溢出显示方案
* @param expanded 是否为展开状态
* @param containerColor FAB 容器的颜色
* @param contentColor FAB 文本和图标颜色通常不需要自己指定会自动依据容器颜色设置
@ -36,20 +31,34 @@ import cn.super12138.todo.utils.VibrationUtils
* @param onClick 点击 FAB 后的回调
* @param modifier `Modifier` 修改器
*/
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun AnimatedExtendedFloatingActionButton(
modifier: Modifier = Modifier,
icon: ImageVector,
fun TodoFloatingActionButton(
text: String,
textOverflow: TextOverflow = TextOverflow.Clip,
expanded: Boolean,
icon: ImageVector,
onClick: () -> Unit,
modifier: Modifier = Modifier,
expanded: Boolean = true,
shape: Shape = FloatingActionButtonDefaults.smallExtendedFabShape,
containerColor: Color = FloatingActionButtonDefaults.containerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
onClick: () -> Unit
interactionSource: MutableInteractionSource? = null,
) {
val view = LocalView.current
FloatingActionButton(
SmallExtendedFloatingActionButton(
text = {
Text(
text = text,
overflow = TextOverflow.Clip
)
},
icon = {
Icon(
imageVector = icon,
contentDescription = null
)
},
onClick = {
VibrationUtils.performHapticFeedback(view)
onClick()
@ -57,27 +66,8 @@ fun AnimatedExtendedFloatingActionButton(
elevation = elevation,
containerColor = containerColor,
contentColor = contentColor,
shape = shape,
interactionSource = interactionSource,
modifier = modifier
) {
Row(
modifier = Modifier.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = icon,
contentDescription = null
)
// Spacer(Modifier.width(if (expanded) 8.dp else 0.dp))
AnimatedVisibility(expanded) {
Row {
Spacer(Modifier.width(8.dp))
Text(
text = text,
maxLines = 1,
overflow = textOverflow
)
}
}
}
}
)
}

View file

@ -23,9 +23,7 @@ import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.Save
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SmallExtendedFloatingActionButton
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
@ -51,6 +49,7 @@ import cn.super12138.todo.ui.TodoDefaults
import cn.super12138.todo.ui.components.ChipItem
import cn.super12138.todo.ui.components.ConfirmDialog
import cn.super12138.todo.ui.components.LargeTopAppBarScaffold
import cn.super12138.todo.ui.components.TodoFloatingActionButton
import cn.super12138.todo.ui.pages.editor.components.TodoCategoryChip
import cn.super12138.todo.ui.pages.editor.components.TodoCategoryTextField
import cn.super12138.todo.ui.pages.editor.components.TodoContentTextField
@ -115,41 +114,33 @@ fun TodoEditorPage(
}
}
BackHandler { checkModifiedBeforeBack() }
BackHandler(onBack = ::checkModifiedBeforeBack)
LargeTopAppBarScaffold(
title = stringResource(if (toDo != null) R.string.title_edit_task else R.string.action_add_task),
scrollBehavior = scrollBehavior,
floatingActionButton = {
with(sharedTransitionScope) {
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier.imePadding()
) {
if (toDo !== null) {
SmallExtendedFloatingActionButton(
text = { Text(stringResource(R.string.action_delete)) },
icon = {
Icon(
imageVector = Icons.Outlined.Delete,
contentDescription = null
)
},
TodoFloatingActionButton(
text = stringResource(R.string.action_delete),
icon = Icons.Outlined.Delete,
expanded = true,
containerColor = MaterialTheme.colorScheme.errorContainer,
onClick = { uiState.showDeleteConfirmDialog = true },
modifier = Modifier.imePadding()
onClick = { uiState.showDeleteConfirmDialog = true }
)
}
SmallExtendedFloatingActionButton(
text = { Text(stringResource(R.string.action_save)) },
icon = {
Icon(
imageVector = Icons.Outlined.Save,
contentDescription = null
)
},
TodoFloatingActionButton(
text = stringResource(R.string.action_save),
icon = Icons.Outlined.Save,
expanded = true,
onClick = {
if (uiState.setErrorIfNotValid()) {
return@SmallExtendedFloatingActionButton
return@TodoFloatingActionButton
} else {
uiState.clearError()
val newTodo = TodoEntity(
@ -163,7 +154,6 @@ fun TodoEditorPage(
}
},
modifier = Modifier
.imePadding()
.sharedElement(
sharedContentState = rememberSharedContentState(key = Constants.KEY_TODO_FAB_TRANSITION),
animatedVisibilityScope = animatedVisibilityScope
@ -172,7 +162,7 @@ fun TodoEditorPage(
}
}
},
onBack = { checkModifiedBeforeBack() },
onBack = ::checkModifiedBeforeBack,
modifier = modifier
) { innerPadding ->
LazyColumn(
@ -183,19 +173,12 @@ fun TodoEditorPage(
.fillMaxSize()
) {
item {
// with(sharedTransitionScope) {
TodoContentTextField(
value = uiState.toDoContent,
onValueChange = { uiState.toDoContent = it },
isError = uiState.isErrorContent,
modifier = Modifier
.fillMaxWidth()
/*.sharedBounds(
sharedContentState = rememberSharedContentState("${Constants.KEY_TODO_CONTENT_TRANSITION}_${toDo?.id}"),
animatedVisibilityScope = animatedVisibilityScope
)*/
modifier = Modifier.fillMaxWidth()
)
// }
}
item {
@ -217,20 +200,13 @@ fun TodoEditorPage(
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
// with(sharedTransitionScope) {
TodoCategoryTextField(
value = uiState.categoryContent,
onValueChange = { uiState.categoryContent = it },
isError = uiState.isErrorCategory,
supportingText = stringResource(uiState.categorySupportingText),
modifier = Modifier
.fillMaxWidth()
/*.sharedBounds(
sharedContentState = rememberSharedContentState("${Constants.KEY_TODO_CATEGORY_TRANSITION}_${toDo?.id}"),
animatedVisibilityScope = animatedVisibilityScope
)*/
modifier = Modifier.fillMaxWidth()
)
// }
}
}

View file

@ -13,10 +13,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Add
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallExtendedFloatingActionButton
import androidx.compose.material3.Text
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.material3.animateFloatingActionButton
import androidx.compose.runtime.Composable
@ -37,6 +34,7 @@ import cn.super12138.todo.constants.Constants
import cn.super12138.todo.logic.database.TodoEntity
import cn.super12138.todo.logic.datastore.DataStoreManager
import cn.super12138.todo.ui.components.ConfirmDialog
import cn.super12138.todo.ui.components.TodoFloatingActionButton
import cn.super12138.todo.ui.pages.main.components.TodoTopAppBar
import cn.super12138.todo.ui.viewmodels.MainViewModel
@ -84,14 +82,9 @@ fun MainPage(
},
floatingActionButton = {
with(sharedTransitionScope) {
SmallExtendedFloatingActionButton(
text = { Text(stringResource(R.string.action_add_task)) },
icon = {
Icon(
imageVector = Icons.Outlined.Add,
contentDescription = null
)
},
TodoFloatingActionButton(
text = stringResource(R.string.action_add_task),
icon = Icons.Outlined.Add,
expanded = expandedFab,
onClick = { toTodoEditPage(null) },
modifier = Modifier

View file

@ -34,8 +34,8 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.IntOffset
import cn.super12138.todo.R
import cn.super12138.todo.logic.datastore.DataStoreManager
import cn.super12138.todo.ui.components.AnimatedExtendedFloatingActionButton
import cn.super12138.todo.ui.components.LargeTopAppBarScaffold
import cn.super12138.todo.ui.components.TodoFloatingActionButton
import cn.super12138.todo.ui.pages.settings.components.category.CategoryItem
import cn.super12138.todo.ui.pages.settings.components.category.CategoryPromptDialog
import kotlinx.coroutines.launch
@ -65,7 +65,7 @@ fun SettingsDataCategory(
scrollBehavior = scrollBehavior,
snackbarHost = { SnackbarHost(snackbarHostState) },
floatingActionButton = {
AnimatedExtendedFloatingActionButton(
TodoFloatingActionButton(
icon = Icons.Outlined.Add,
text = stringResource(R.string.action_add_category),
expanded = isExpanded,
@ -81,7 +81,7 @@ fun SettingsDataCategory(
state = listState,
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
.padding(innerPadding) //TODO: 可能需要清除屏幕边距
) {
if (categories.isEmpty()) {
item {