我们的todo 只能添加随机的todo 非常的不智能。下面来完善他。让他支持到可以进行添加自定义的项目
这里的阴影还没开始使用。
TodoComponents.kt
package com.anguomob.jecpack.activity.compose.todo.one
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.*
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import com.anguomob.jecpack.activity.compose.todo.bean.ToDoIcon
import com.anguomob.jecpack.activity.compose.todo.bean.TodoItem
@Composable
fun ToDoItemInputBackground(
modifier: Modifier = Modifier,
content: @Composable RowScope.() -> Unit,
elevatioon: Boolean
) {
//帧动画形式展示Surface底部的阴影
val animatedElevation by animateDpAsState(
targetValue = if (elevatioon) 1.dp else 0.dp,
TweenSpec(300)
)
Surface(
color = MaterialTheme.colors.onSurface.copy(alpha = 0.05f),
shape = RectangleShape,
elevation = animatedElevation
) {
Row(modifier = modifier.animateContentSize(animationSpec = TweenSpec(300))) {
content()
}
}
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun TodoInputText(
text: String,
onTextChanged: (String) -> Unit,
onImeAction: () -> Unit,
modifier: Modifier = Modifier,
) {
val keyboardController = LocalSoftwareKeyboardController.current
TextField(
value = text,
onValueChange = onTextChanged,
modifier = modifier,
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.Transparent),
maxLines = 1,
//配置软键盘
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = {
onImeAction()
//点击完成之后 隐藏键盘
keyboardController?.hide()
})
)
}
@Composable()
fun TodoEditButton(
onClick: () -> Unit,
text: String,
modifier: Modifier = Modifier,
enable: Boolean = true
) {
TextButton(
onClick = onClick,
shape = CircleShape,
colors = ButtonDefaults.buttonColors(),
modifier = modifier,
enabled = enable
) {
Text(text)
}
}
@Composable
fun TodoItemEntryInput(onItemComplete: (TodoItem) -> Unit) {
val (text, setText) = remember {
mutableStateOf("")
}
val (icon, setIcon) = remember {
mutableStateOf(ToDoIcon.Default)
}
//icon是否可一件取决于文本是否有内容
val iconsVisible = text.isNotBlank()
//点击add
val submit = {
onItemComplete(TodoItem(text, icon))
setText("")
setIcon(ToDoIcon.Default)
}
TodoItemInput(
text = text,
onTextChange = setText,
icon = icon,
onIconChange = setIcon,
iconsVisible = iconsVisible,
submit = submit,
)
}
@Composable
fun TodoItemInput(
text: String,
onTextChange: (String) -> Unit,
icon: ToDoIcon,
onIconChange: (ToDoIcon) -> Unit,
iconsVisible: Boolean,
submit: () -> Unit
) {
Column {
Row(
Modifier
.padding(horizontal = 16.dp)
.padding(top = 16.dp)
) {
TodoInputText(
text = text,
modifier = Modifier
.weight(1f)
.padding(end = 8.dp),
onTextChanged = onTextChange,
onImeAction = submit
)
TodoEditButton(
onClick = submit,
text = "Add",
modifier = Modifier.align(Alignment.CenterVertically),
enable = text.isNotBlank()
)
}
AnimatedIconRow(
visible = iconsVisible,
icon = icon,
onIconChange = onIconChange,
modifier = Modifier.padding(8.dp)
)
}
}
//一排图标 根据文本框是否有内容 自动弹起收缩
@Composable
fun AnimatedIconRow(
modifier: Modifier = Modifier,
visible: Boolean,
icon: ToDoIcon,
onIconChange: (ToDoIcon) -> Unit
) {
val enter = remember {
fadeIn(animationSpec = TweenSpec(300, easing = FastOutLinearInEasing))
}
val exit = remember {
fadeOut(animationSpec = TweenSpec(100, easing = FastOutSlowInEasing))
}
//最小高度16dp
AnimatedVisibility(visible = visible, enter = enter, exit = exit, modifier = modifier) {
IconRow(icon = icon, onIconChange = onIconChange)
}
}
@Composable
fun IconRow(icon: ToDoIcon, onIconChange: (ToDoIcon) -> Unit, modifier: Modifier = Modifier) {
Row(modifier = modifier) {
for (todoIcon in ToDoIcon.values()) {
SelectableIconButton(
icon = todoIcon.imageVector,
iconContentDescription = todoIcon.contentDescription,
onIconSelect = { onIconChange(todoIcon) },
isSelected = todoIcon == icon
)
}
}
}
@Composable
fun SelectableIconButton(
icon: ImageVector,
iconContentDescription: Int,
onIconSelect: () -> Unit,
isSelected: Boolean,
modifier: Modifier = Modifier
) {
//图标选中和未选中 颜色不一样
val tint = if (isSelected) {
MaterialTheme.colors.primary
} else {
MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
}
val enter = remember {
fadeIn(animationSpec = TweenSpec(300, easing = FastOutLinearInEasing))
}
val exit = remember {
fadeOut(animationSpec = TweenSpec(100, easing = FastOutSlowInEasing))
}
TextButton(onClick = onIconSelect, modifier = modifier) {
Column {
Icon(
imageVector = icon,
tint = tint,
contentDescription = stringResource(id = iconContentDescription)
)
//最小高度16dp
AnimatedVisibility(visible = isSelected, enter = enter, exit = exit) {
Box(
Modifier
.padding(top = 3.dp)
.width(icon.defaultWidth)
.height(1.dp)
.background(tint)
)
}
}
}
}
TodoScreen.kt
package com.anguomob.jecpack.activity.compose.todo.one
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import com.anguomob.jecpack.R
import com.anguomob.jecpack.activity.compose.todo.bean.ToDoIcon
import com.anguomob.jecpack.activity.compose.todo.bean.TodoItem
import com.anguomob.jecpack.activity.compose.todo.viewmodel.TodoViewModel
import generateRandomTodoItem
import java.util.*
import kotlin.random.Random
@Composable
fun TodoActivityScreen(todoViewModel: TodoViewModel ) {
// val items = listOf(
// TodoItem("Learn compose", ToDoIcon.Event),
// TodoItem("Take a CodeLab"),
// TodoItem("Apply state", ToDoIcon.Done),
// odoItem("Build dynamic UIs", ToDoIcon.Square),
val items: List<TodoItem> by todoViewModel.todoItems.observeAsState(listOf())
TodoScreen(items = items, onAddItem = {
todoViewModel.addItem(it)
}, onItemClick = {
todoViewModel.removeItem(it)
})
}
@Composable
fun TodoScreen(
items: List<TodoItem>,
onAddItem: (TodoItem) -> Unit,
onItemClick: (TodoItem) -> Unit
) {
Column() {
//输入框 外加一个灰色背景
ToDoItemInputBackground(content = {
TodoItemEntryInput(onItemComplete = onAddItem)
}, elevatioon = true)
LazyColumn(
modifier = Modifier
.weight(1f)
) {
items(items) {
TodoRow(it, modifier = Modifier.fillParentMaxWidth(), onItemClick = onItemClick)
}
}
Button(
onClick = {
onAddItem(generateRandomTodoItem())
},
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
) {
Text("新建TODO")
}
}
}
@Composable
fun TodoRow(todo: TodoItem, modifier: Modifier = Modifier, onItemClick: (TodoItem) -> Unit) {
Row(
modifier = modifier
.padding(horizontal = 16.dp, vertical = 8.dp)
.clickable { onItemClick(todo) },
//子元素水平均匀分发
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(todo.task)
val iconAlpha = remember(todo.id) {
randomTint()
}
Icon(
imageVector = todo.icon.imageVector,
tint = LocalContentColor.current.copy(alpha = iconAlpha),
contentDescription = stringResource(id = todo.icon.contentDescription)
)
}
}
private fun randomTint(): Float {
val number = Random.nextFloat().coerceIn(0.3f, 0.9f)
return number
}
数据bean等类容在这里
Kotlin Compose Todo小项目 删除添加项目 ,认识状态提升_安果移不动的博客-CSDN博客
效果就是通过点击
add之后可以选择图标和文案来进行写todo项目
关于阴影 可以重点关注这个