从0开始搭建一个APP:compose搬砖的第一天

之前有笔记在整这个玩意,搭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的写法估计就是:

ini 复制代码
<TextView
    android:textSize="16sp"
    android:gravity="center"
    android:text="标题"
    android:layout_width="match_parent"
    android:layout_height="44dp"/>

但是compose 的:

less 复制代码
Text(text = "标题", modifier = Modifier.fillMaxWidth().height(44.dp).align(Alignment.Center))

就会发现,align这个函数导入不了包,哈?这不科学。

可以看到,这个属性,只有在box,column,row中有,okoko,所以,这种得这么写:

ini 复制代码
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxWidth().height(44.dp)){
    Text(text = "标题")
}

下面是效果:

compose 没有margin,只有padding

有这个想法的原因是,一个习惯,其实官方并不建议我们用margin去做view的间距,因为我们view的计算宽高和布置位置的时候,要计算margin 和padding的啊,官方建议我们用:

ini 复制代码
<Space
    android:layout_width="wrap_content"
    android:layout_height="10dp"/>

这个调调做view的间距,而在compose 中体现的极其明显,他直接把margin 给干没了,而compose 中也提供了Space,那就是:

ini 复制代码
Spacer(modifier = Modifier.height(10.dp))

所以,个人感觉,有些人说用padding,感觉一条路走到黑了。

要分割线还是用canvas自己画?

因为是做设置类型的界面。这种界面,都知道,喜欢画一根分割线,Android view 里面,做分隔线还不简单:

  • 可以是view 设置背景
  • 可是LinearLayoutCompat 设置divider。
  • 可以是recycleview 设置分割线。
  • viewGroup 的组合里面,我们为了体现技术(装B),也会用canvas 自己画一根直线。

实现方式多种多样,但是在compose 搬砖的第一天,这个玩意,怎么有点不丝滑?我好像没有记起来有这个调调,但是也不复杂,毕竟,我可以自己画一根不就可以了吗?compose 不提供不也正常吗,是吧。

scss 复制代码
Canvas(modifier = Modifier.fillMaxWidth().height(1.dp), onDraw = {
    drawRect(Color.Red)
})

emmm?可惜这个函数里面没有画RGB 纯颜色的,只要高度足够小,纯颜色,也可以是分割线,是吧。当我把这个写完的时候,突然想起,Android 里面并没有分割线的定义,都是叫divider:

scss 复制代码
Divider()

这个3个入参:

  • modifier 控制宽高,相对位置等杂七杂八的。
  • thickness 分割线的高度
  • color 分割线的颜色。

我们再来看看divider的源码:

scss 复制代码
@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 获取参数的例子。

kotlin 复制代码
class ComposeDebugViewModel:BaseViewModel(){
    var debugStare= mutableStateOf("name")
}
kotlin 复制代码
@Preview(showBackground = true)
@Composable
fun debugPage(){
    var name by remember {
        viewModel.debugStare
    }
    Text(text = name, modifier = Modifier.clickable {
        name="${System.currentTimeMillis()}"
    })
}

功能很简单,每次点击text,就将text 上的文本刷新为 点击时候的时间戳,但是就会发现,预览不了,这就涉及到一个名称,叫状态提升了,我们将点击事件和指,通过外部传入进来,并且是设置默认值,就可以预览了。

kotlin 复制代码
    @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吗?

scss 复制代码
implementation("androidx.compose.runtime:runtime-livedata:1.5.4")

runtime 的?我们Kotlin导入到runtime 的包还少吗? 我们将上面的代码再次改造一下。

kotlin 复制代码
    @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的学习是差不多的,要把格局打开,就是想象力得打开,打开了就会发现,很多东西,他其实已经存在了。

相关推荐
- 羊羊不超越 -19 分钟前
App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)
android·ios·harmonyos
wk灬丨1 小时前
Android Kotlin Flow 冷流 热流
android·kotlin·flow
千雅爸爸1 小时前
Android MVVM demo(使用DataBinding,LiveData,Fresco,RecyclerView,Room,ViewModel 完成)
android
晨曦_子画2 小时前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin
孤客网络科技工作室2 小时前
AJAX 全面教程:从基础到高级
android·ajax·okhttp
Mr Lee_3 小时前
android 配置鼠标右键快捷对apk进行反编译
android
顾北川_野4 小时前
Android CALL关于电话音频和紧急电话设置和获取
android·音视频
&岁月不待人&4 小时前
Kotlin by lazy和lateinit的使用及区别
android·开发语言·kotlin
Winston Wood6 小时前
Android Parcelable和Serializable的区别与联系
android·序列化