Kotlin Compose 完善toDo项目 Surface 渲染背景 与阴影

我们的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项目

关于阴影 可以重点关注这个

猜你喜欢

转载自blog.csdn.net/mp624183768/article/details/125454574