Compose 1

107 阅读2分钟

Compose 1

可组合函数

  • Compose是围绕可组合函数(Composable)构建的,只需要在可组合函数中描述界面和提供数据依赖,而不必关注界面的构建过程(初始化、添加到父布局等);

  • 添加@Composable注解即可声明一个可组合函数;

  • 可组合函数只能从其他可组合函数调用

  • 借助@Preview注解,可以在AS中预览可组合函数,且因为该注解必须用于不接受参数的可组合函数,因此需要创建一个无参可组合函数.

    @Composable
    fun MessageCard(name: String) {
        Text(text = "Hello $name!")
    }
    ​
    @Preview
    @Composable
    fun PreviewMessageCard() {
        MessageCard("Android")
    }
    

布局

垂直排列

@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}
​
@Preview
@Composable
fun MessageCardPreview() {
    MessageCard(msg = Message("author_preview", "body_preview"))
}

水平排列

@Composable
fun MessageCard(msg: Message) {
    Row {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}
​
@Preview
@Composable
fun MessageCardPreview() {
    MessageCard(msg = Message("author_preview", "body_preview"))
}

堆叠排列

@Composable
fun MessageCard(msg: Message) {
    Box {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}
​
@Preview
@Composable
fun MessageCardPreview() {
    MessageCard(msg = Message("author_preview", "body_preview"))
}

配置布局

@Composable
fun MessageCard(msg: Message) {
    Row {
        Image(
            painter = painterResource(id = R.drawable.ic_launcher_foreground),
            contentDescription = "image"
        )
        Column {
            Text(text = msg.author)
            Text(text = msg.body)
        }
    }
}
​
@Preview
@Composable
fun MessageCardPreview() {
    MessageCard(msg = Message("author_preview", "body_preview"))
}

问题:

元素间距不合理

图片过大

@Composable
fun MessageCard(msg: Message) {
    Row {
        Image(
            painter = painterResource(id = R.drawable.ic_launcher_foreground),
            contentDescription = "image",
            modifier = Modifier
                //尺寸
                .size(40.dp)
                //裁剪
                .clip(CircleShape)
        )
​
        //横向间距
        Spacer(modifier = Modifier.width(8.dp))
        Column {
            Text(text = msg.author)
            //纵向间距
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body)
        }
    }
}
​
@Preview
@Composable
fun MessageCardPreview() {
    MessageCard(msg = Message("author_preview", "body_preview"))
}

列表和动画

  1. 列表
@Composable
fun MessageList(messageList: List<Message>) {
    LazyColumn {
        items(messageList) { message ->
            MessageCard(message)
        }
    }
}
​
@Preview
@Composable
fun MessageListPreview() {
    LearnComposeTheme {
        Surface {
            val messageList: MutableList<Message> = mutableListOf()
            messageList.add(Message("author1", "body1"))
            messageList.add(Message("author2", "body2"))
            messageList.add(Message("author3", "body3"))
            messageList.add(Message("author4", "body4"))
            MessageList(messageList = messageList)
        }
    }
}
  1. 动画

    compose中使用rember存储本地状态,这个值更新时,系统会自动重新绘制使用此状态的可组合项(及其子项)

    var isExpand by remember { mutableStateOf(false) }
    
    • remember确保mutableStateOf(false)创建的MutableState对象在充重组过程中保持其状态
    • by将isExpand的访问和修改委托给MutableStateOf对象
    • 通过by关键字,isExpand的getter和setter实际是通过MutableState对象实现的.当访问isExpand时,实际上是在调用MutableState对象的value属性的的getter方法,修改时用的就是setter方法,此时会触发Compose系统进行重组,从而更新UI.
    @Composable
    inline fun <T> remember(crossinline calculation: @DisallowComposableCalls () -> T): T =
        currentComposer.cache(false, calculation)
    

    我们来看remember的实现:

    • @Composable表示是可组合函数,只能在另一个可组合函数中调用
    • inline表示这是个内联函数,编译时会把函数的代码体直接替换到调用点,从而消除函数调用的开销
    • 表示泛型,rember函数可以记住任何类型的值
    • crossinline用来修饰lambda,表示lambda不能有非局部返回,确保在被内联时不会意外的从外部函数返回.
    • @DisallowComposableCalls表示这个lambda不能调用其他可组合函数,确保calculation中的代码不会破坏Compose的重组机制