4.2 Compose 可构建容器函数
Compose 支持构建容器函数,容器函数类似于 Theme 主题,可以将一些基础的设置信息放在容器函数中,这样放入这个容器函数中的 Composable 函数就会根据设置的信息进行绘制、渲染。举个简单的栗子:
// code 5 // 声明一个容器函数 @Composable fun MyApp(content: @Composable () -> Unit) { MaterialTheme() { Surface(color = Color.Yellow, modifier = Modifier.padding(10.dp)) { content() } } } // 实际运用 MyApp { Text(text = "被容器函数所修饰的 Text") }
所有放入 MyApp 容器中的 Composable 函数都会带上容器函数中设置的属性。这样可提高代码复用性和可读性。
4.3 Compose 状态初探
Compose 的核心内容就是响应 state 状态的改变。Compose 通过调用 Composable 函数可以将 data 数据展示在 UI 上,Compose 本身也提供了工具去观察 data 数据的变化,从而可以自动地回调展示 UI,这一过程官方称为重组,前面也有说到。可以理解为更新 UI。
在 Composable 函数内部我们可以使用 mutableStateOf 方法去添加一个可变的 state,为了避免每次重组都会出现不同的状态,所以可以用 remember 记住这个可变状态。
// code 6 @Composable fun Counter() { val count = remember { mutableStateOf(0)} // 初始化为 0 Button(onClick = { count.value++ }) { Text(text = "已点击了 ${count.value} 次!") } }
这样每次点击 Button,都会更新点击的次数值。
4.4 Compose 列表初探
列表布局使用频率还是比较高的,像 ListView 和 RecyclerView 都是耳熟能详的用于展示列表的 View 控件。那么 LazyColumn 就相当于 Compose 中的 RecyclerView,用于展示可滑动的长列表。它提供了 items API 用于展示简单的列表布局。
// code 7 @Composable fun NameList(names: List<String>, modifier: Modifier = Modifier) { LazyColumn(modifier = modifier) { items(items = names) { name -> Greeting(name = name) Divider(color = Color.Black) // 分割线类对象 } } }
然而,LazyColumn 不会像 RecyclerView 一样缓存列表中的布局,而是在滚动浏览它时,它会渲染新的列表 View,并没有回收机制,但是相比于实例化 Android View,渲染 Composable UI 组件效率更高。
4.5 Compose 自定义主题
Compose 中有自带的一些主题,比如 MaterialTheme,被这些 Theme 包裹,就可以呈现出这些 Theme 所设置的属性了。当然也可以单独将这些 Theme 中某些属性拿出来,比如字体。然后就可以使用该主题下设置的各种字体样式了,同样的还有色值:
// code 8 @Composable fun Greeting(name: String) { val greetingTypography = MaterialTheme.typography // 获取 MaterialTheme 字体样式 val greetingColors = MaterialTheme.colors // 获取 MaterialTheme 色值 Text(text = "Hello $name", color = greetingColors.onBackground, // 使用 MaterialTheme 的 onBackground 色值 style = greetingTypography.body2) }
还可以调用 copy 方法复制某主题的样式,然后在此基础上改写自己的一些样式属性:
// code 9 @Composable fun Greeting(name: String) { val customStyle = MaterialTheme.typography.h5.copy(color = Color.Green) Text(text = "Hello $name", style = customStyle) }
如何自定义一个自己的 Theme?其实也很简单,下面是一个例子:
// code 10 // 主要方法,被此方法包裹的 Composable 函数都会被设置为自定义主题 @Composable fun CustomTheme( darkTheme: Boolean = isSystemInDarkTheme(), // 默认根据系统来设置是否为暗夜模式 content: @Composable () -> Unit // 被传入的 Composable 函数 ){ val colors = if (darkTheme) { DarkColors } else { LightColors } MaterialTheme(colors = colors) { // 将设置好的色值传入 content() } } private val DarkColors = darkColors( // 暗夜模式下的色值 primary = Red300, primaryVariant = Red700, onPrimary = Color.Black, secondary = Red300, onSecondary = Color.Black, error = Red200 ) private val LightColors = lightColors( // 白天模式下的色值 primary = Red700, primaryVariant = Red900, onPrimary = Color.White, secondary = Red700, secondaryVariant = Red900, onSecondary = Color.White, error = Red800 )
是不是觉得简单?是的,在 Compose 中自定义一个主题就是这么简单。
5. 编程思想
再来说一说官方文档里提到的 Compose 的编程思想吧。它采用的是声明性界面模型,该模型工作原理是先从开始生成整个屏幕,然后仅执行必要的更改。重组就是使用新数据再次调用 Composable 函数,从而进行更新的。当然重组过程仅调用可能已更改的函数或 lambda,而跳过其余函数或 lambda,所以 Compose 可以高效地重组。
其中,官方建议在更新时,不要依赖于执行 Composable 函数所产生的附带效应,因为可能会跳过函数的重组。附带效应指的是对应用的其余可见部分的任何更改。危险的附带效应有1)写入共享对象的属性(这个应该是怕有其他的逻辑正在读取共享对象属性来更新 UI 等,使得 UI 变化不准确。);2)更新 ViewModel 中的可观察项(原理同1));3)更新 SharedPreference(原理同1))。(不是很理解,可能日后真正使用后会更有体会吧~欢迎一起讨论)
Composable 函数可能会像每一帧一样频繁地重新执行,例如在呈现动画时。Composable 函数应快速执行,避免在播放动画期间出现卡顿。如果需要执行耗时操作,如从 SharedPreference 中读取数据,那么建议在后台协程中处理,然后使用回调传递当前值来触发更新。还有几个值得注意的 Tips:
1、Composable 函数可以按任何顺序执行 如果某个 Composable 函数中包含有几个 Composable 函数,那么这些 Composable 函数可能按任何顺序运行,Compose 会识别出哪些界面元素的优先级高于其他的界面元素,从而优先绘制这些元素。
2、 Composable 函数可以并行运行 Compose 可以通过并行运行 Composable 函数来优化重组。所以,Compose 可以利用多个核心,并以较低的优先级运行 Composable 函数。因此,Composable 函数可能会在后台线程池中执行。调用某个 Composable 函数时,调用可能发生在与调用方不同的线程中。
3、重组会跳过尽可能多的内容 Compose 会尽力只重组需要更新的部分,每个 Composable 函数和 lambda 又可以自行重组更新。Compose 若在一次重组时发现参数又更新了,则会取消当前的重组,并用新参数重新开始。
官方推荐将 Composable 函数写在顶级函数,方便以后复用。
Compose 博大精深,许多概念性的东西并没有理解得很透彻,还需慢慢实践才能得出真知啊!欢迎留言交流,互相学习!
ps. 简单的 Demo:gitee.com/xiuzhizhu/C…
官方教程网站:developer.android.google.cn/courses/pat…
参考文献
- Jetpack Compose 1.0 正式发布!打造原生 UI 的 Android 现代工具包
- Jetpack Compose 基础知识
- Compose 编程思想
尾巴:这是 Compose 系列笔记的首篇,相信细心的同学也发现了,这篇笔记是根据官方教程网站上的学习路线进行记录学习的。自己在学习的过程中,遇到不明白的地方也会查阅大量的资料进行补充,喜欢的话,欢迎分享转发加关注~