Jetpack Compose 自定义可展开的条目,带动画哦

518 阅读2分钟

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战

var expand by remember { mutableStateOf(true) }

定义一个变量用来保存展开收起状态

Column(
    modifier = Modifier
        .padding(vertical = 6.dp, horizontal = 6.dp)
        .wrapContentSize()
        .animateContentSize(
            tween(500)
        ),
)

Column就像LinearLayout的orientation="vertical"
wrapContentSize()这个应该大家都很熟悉

animateContentSize的作用是当布局更改大小时,此修改器将设置其自身大小的动画。这允许父修改器观察平滑的大小更改,从而导致整体连续的视觉更改

这样外层的布局写完了,接着写展开和收缩的内容

content: @Composable ColumnScope.() -> Unit,
expandContent: @Composable ColumnScope.() -> Unit

接收两个参数,分别是展开的内容和收缩的内容 content:收缩的 expandContent:展开的

ColumnScope是一个接口作用是:
根据元素相对于列中其他加权同级元素的权重,调整元素高度的大小。父元素将在测量未加权的子元素后分割剩余的垂直空间,并根据该权重进行分配。当fill为true时,元素将被强制占据分配给它的整个高度。否则,允许元素更小-这将导致列更小,因为未使用的分配高度不会重新分配给其他同级。

接收的参数赋值给Column{}

   Column(content = content,Modifier.clickable { expand = !expand })

if (expand) {
    Column(content = expandContent)
}

Modifier.clickable { expand = !expand }
给content设置展开的点击事件

判断expand是否显示展开的内容

使用方法

ExpandContent(
    content = {
        Text("消息")
    }, expandContent = {
        Text("消息1")
        Text("消息2")
        Text("消息3")
        Text("消息4")
        Text("消息5")
        Text("消息6")
    })

0600251b871459dc3c38a00d6746ef1.jpg

但是这样并不好看,我们美化一下,用Card包装起来

美化

自定义一个沉浸的Crad

@Composable
fun ImmerseCard(
    modifier: Modifier = Modifier,
    shape: Shape = RoundedCornerShape(16.dp),
    backgroundColor: Color = CustomTheme.colors.listItem,
    contentColor: Color = contentColorFor(backgroundColor),
    border: BorderStroke? = null,
    elevation: Dp = 0.dp,
    content: @Composable () -> Unit
) {
    Card(
        modifier = modifier,
        shape = shape,
        backgroundColor = backgroundColor,
        contentColor = contentColor,
        elevation = elevation,
        border = border,
        content = content
    )
}

包装起来

ImmerseCard{
    Column(content = content, modifier = Modifier.clickable { expand = !expand })
}

完整代码

给条目加上图标和标题

@Composable
fun TypeItem(
    text: String,
    icon: Int,
) {
    Row(
        verticalAlignment = Alignment.CenterVertically, modifier = Modifier
            .fillMaxWidth()
    ) {
        Image(
            painterResource(icon), text, Modifier
                .padding(12.dp, 8.dp, 8.dp, 8.dp)
                .size(26.dp)
        )
        Text(
            text = text,
            modifier = Modifier.padding(start = 26.dp),
            fontSize = 21.sp,
            color = CustomTheme.colors.textPrimary
        )
    }
}

封装后的完整代码

@Composable
fun ExpandContent(
    content: @Composable ColumnScope.() -> Unit,
    expandContent: @Composable ColumnScope.() -> Unit
) {
    var expand by remember { mutableStateOf(false) }
    Column(
        modifier = Modifier
            .padding(vertical = 6.dp, horizontal = 6.dp)
            .wrapContentSize()
            .animateContentSize(
                tween(500)
            ),
    ) {

        ImmerseCard{
            Column(content = content, modifier = Modifier.clickable { expand = !expand })
        }

        if (expand) {
            Column(content = expandContent)
        }
    }
}

使用方法


ImmerseCard(
    modifier = Modifier.padding(
        vertical = 6.dp,
        horizontal = 12.dp
    )
) {
    AnimateContent(
        content = {
            TypeItem("帖子通知", R.drawable.ic_notice)
        }, expandContent = {


            Text("消息1")
            Text("消息2")
            Text("消息3")
            Text("消息4")
            Text("消息5")
            Text("消息6")
        })
}

效果图

ezgif.com-gif-maker (5).gif