之前有笔记在整这个玩意,搭compose的环境,设置预览啥的,由于这是新项目,可是compose的接入仍是经过几次打听来着,终究确认下来,然后便是Jenkins上环境的处理,这个玩意,不是说,接入就接入了,许多环境需要处理,所以说,2023年11月1日才真正写第一行compose的代码,也是各种因素协调的成果。
再提一下,由于之前这个系列断更的东西有点多,所以就没有序号了。
compose的相关根底和版本相关的根底,就不占用资源了,直接翻上一篇从0开端建立一个APP:(4) BaseUI层MVVM和compose的接入。
无论是从各个大佬的书籍仍是blog,大的方向仍是翻了一遍,个人感觉,compose 是UI解决方案这种定义和Android离得特别远,像Android 的应用端的大多数工作量仍是在UI开发上,flutter 也差不多,结合Kotlin的开发经历,我觉得compose 其实在Android上他能够理解成供给了特别多Kotlin作用域函数的自定义view,这一点,在今天的搬砖中感受得特别明显。当咱们无法对UI行为进行笼统的时分,就感觉他不落地。
平常,Android中写一个界面,存在着各个细分领域,可是compose就不相同了,他啥都有,可是全赖想象力,便是写代码都时分,得有人一直说,格式得翻开,想象力得翻开。你得自己拼装,并且知道自己拼装的每一步是干什么,下一步得干什么,而之前的Android view的写法就不是这个样子,之前是终究汇总成一个成果,而compose走一步变一步,这就要求,咱们对自定义view或许说对大多数view的制作过程了解得特别清晰。
今天和一个大佬唠嗑,说1天看完一本书,第二天就能够上手干,说自定义view强的话就能够,大佬觉得自己第2天就真的能够上手干了,emmmm,自身没有多少问题,便是有点打手。
个人觉得,compose 从Android 进阶的视点上来说,是能够学习运用的,他这种根据状况的改写机制,特别像viewbinding 或许像 Html 经过数据生成dev 的那种感觉,并且是进阶版本,经过对比学习,肯定是能够更好的把握UI的制作的,并且现在各种自定义系统,神仙打架,真的需要将技术概念抽离出来,便利后期学习搬砖。
正文
okokok,水了这么多字,仍是写正文。
Text 怎么相对居中?
业务场景是,界面顶部有一个标题栏,并且标题栏上面就一个文本。那么换成Android view的写法估量便是:
<TextView
android:textSize="16sp"
android:gravity="center"
android:text="标题"
android:layout_width="match_parent"
android:layout_height="44dp"/>
可是compose 的:
Text(text = "标题", modifier = Modifier.fillMaxWidth().height(44.dp).align(Alignment.Center))
就会发现,align这个函数导入不了包,哈?这不科学。
能够看到,这个特点,只需在box,column,row中有,okoko,所以,这种得这么写:
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxWidth().height(44.dp)){
Text(text = "标题")
}
下面是作用:
compose 没有margin,只需padding
有这个想法的原因是,一个习气,其实官方并不主张咱们用margin去做view的距离,由于咱们view的核算宽高和安置方位的时分,要核算margin 和padding的啊,官方主张咱们用:
<Space
android:layout_width="wrap_content"
android:layout_height="10dp"/>
这个调调做view的距离,而在compose 中表现的极其明显,他直接把margin 给干没了,而compose 中也供给了Space,那便是:
Spacer(modifier = Modifier.height(10.dp))
所以,个人感觉,有些人说用padding,感觉一条路走到黑了。
要分割线仍是用canvas自己画?
由于是做设置类型的界面。这种界面,都知道,喜爱画一根分割线,Android view 里边,做分隔线还不简略:
- 可所以view 设置背景
- 可是LinearLayoutCompat 设置divider。
- 可所以recycleview 设置分割线。
- viewGroup 的组合里边,咱们为了表现技术(装B),也会用canvas 自己画一根直线。
实现方式多种多样,可是在compose 搬砖的第一天,这个玩意,怎么有点不丝滑?我如同没有记起来有这个调调,可是也不复杂,毕竟,我能够自己画一根不就能够了吗?compose 不供给不也正常吗,是吧。
Canvas(modifier = Modifier.fillMaxWidth().height(1.dp), onDraw = {
drawRect(Color.Red)
})
emmm?可惜这个函数里边没有画RGB 纯色彩的,只需高度满足小,纯色彩,也可所以分割线,是吧。当我把这个写完的时分,突然想起,Android 里边并没有分割线的定义,都是叫divider:
Divider()
这个3个入参:
- modifier 控制宽高,相对方位等杂七杂八的。
- thickness 分割线的高度
- color 分割线的色彩。
咱们再来看看divider的源码:
@Composable
fun Divider(
modifier: Modifier = Modifier,
thickness: Dp = DividerDefaults.Thickness,
color: Color = DividerDefaults.color,
) {
val targetThickness = if (thickness == Dp.Hairline) {
(1f / LocalDensity.current.density).dp
} else {
thickness
}
Box(
modifier
.fillMaxWidth()
.height(targetThickness)
.background(color = color)
)
}
他自己整了一个box,设置了一个背景,分割线的高度便是box的高度,emmmmm?果真朴实无华,挺懊悔自己想的怎么多,每天上一当,当当不相同。
要state 仍是liveData?
compose 是根据state更新UI的,而咱们MVVM通常主张咱们运用LiveData,liveData的长处蛮多的,最起码的是不会出现生命周期问题,那么这两个能不能兼容呢?当然是能够了。 咱们先来看一个经过viewModel 获取参数的例子。
class ComposeDebugViewModel:BaseViewModel(){
var debugStare= mutableStateOf("name")
}
@Preview(showBackground = true)
@Composable
fun debugPage(){
var name by remember {
viewModel.debugStare
}
Text(text = name, modifier = Modifier.clickable {
name="${System.currentTimeMillis()}"
})
}
功用很简略,每次点击text,就将text 上的文本改写为 点击时分的时刻戳,可是就会发现,预览不了,这就涉及到一个称号,叫状况提升了,咱们将点击事情和指,经过外部传入进来,并且是设置默认值,就能够预览了。
@Composable
override fun pageContent() {
var name by remember {
viewModel.debugStare
}
debugPage(name){
name="${System.currentTimeMillis()}"
}
}
@Preview(showBackground = true, showSystemUi = true)
@Composable
fun debugPage(name:String="测试数据",clickable:()->Unit={}){
Text(text = name, modifier = Modifier.clickable {
clickable
})
}
class ComposeDebugViewModel:BaseViewModel(){
var debugStare= mutableStateOf("name")
}
这么一改,咱们就将预览和正式的UI经过数据拆解出来了。可是呢,咱们仍是没有用到LiveData.
为了全都要,咱们需要导入一个maven,不便是导入个一个maven吗?
implementation("androidx.compose.runtime:runtime-livedata:1.5.4")
runtime 的?咱们Kotlin导入到runtime 的包还少吗? 咱们将上面的代码再次改造一下。
@Composable
override fun pageContent() {
val name by viewModel.debugStare.observeAsState("默认值")
debugPage(name){
viewModel.debugStare.value="${System.currentTimeMillis()}"
}
}
@Preview(showBackground = true, showSystemUi = true)
@Composable
fun debugPage(name:String="测试数据",clickable:()->Unit={}){
Text(text = name, modifier = Modifier.clickable {
clickable
})
}
class ComposeDebugViewModel:BaseViewModel(){
var debugStare= MutableLiveData("name")
}
主要的改动点仍是经过observeAsState 函数将LiveData转化成了state,一起name 的更新就得用LiveData进行更新了。这个便是compose上的单向数据流的概念,有一个经典的MVI的图,说对便是那个调调,详细实现上,最简略的便是这种。
由于Livedata的能够转换为state,这也是不没有用Flow的原因,嗯,感觉简略的接口恳求LiveData 或许更好。
总结
OK,先水到这,主要是论述了一些第一次开发或许遇到的简略问题,也没有啥知识点,水一下,也挺好。再提一嘴,compose和Kotlin的学习是差不多的,要把格式翻开,便是想象力得翻开,翻开了就会发现,许多东西,他其实已经存在了。