Android Jetpack Compose中modifier.与Modifier.方法调用差异及原理问询
Q1:小写modifier.为啥会让父Column的垂直居中失效?但Column里用modifier.padding却正常?
先理清楚两个关键逻辑:
- 父Column的
verticalAlignment = Alignment.CenterVertically是Column自身的布局规则,和Modifier是两套独立的逻辑,它负责让Column内部的子组件在垂直方向居中摆放。 Modifier(大写)是创建全新的约束实例,而modifier(小写)是父组件传给当前Composable的已有约束链。
你的场景里,当Text用Modifier.padding()时,Text的约束是全新的,没有抢占额外空间,所以Column的居中规则能正常把Text摆到中间。但如果Text用modifier.padding(),这里的modifier如果是父Column传过来的、带fillMaxSize()这类占满空间的约束,那么追加padding后,Text会撑满整个Column的空间——此时Column的居中还是生效的,但Text本身和Column一样大,你看到的Text内容的位置其实是Text自己的内部布局,自然就看不到“居中”的视觉效果了。
至于Column里用modifier.padding()正常生效,是因为这个操作是给Column自身的约束链追加padding,和Column内部的子组件对齐规则不冲突,框架会先处理Column的padding,再在内部应用居中逻辑,所以没问题。
Q2:既然小写modifier.是操作传入的父对象,为啥Column用它不会影响父组件?
核心原因是Compose的Modifier是不可变的。你调用modifier.padding()的时候,根本没修改传入的那个modifier实例,而是返回了一个全新的Modifier实例——这个新实例包含了原约束链的所有规则,再加上你新增的padding。
所以Column接收父组件的modifier参数后,调用方法得到的新实例,只会作为Column自己的约束交给框架,原来的父组件的Modifier实例完全没被改动,自然不会影响上游的组件。这和Kotlin里不可变对象的逻辑一致:所有“修改”操作都是生成新对象,原对象纹丝不动。
Q3:该建立啥认知模型?Composable是函数而非对象吗?
没错,Composable就是函数,不是类的实例。Compose是声明式UI框架,UI是通过调用一系列Composable函数构建的,框架会根据这些函数调用生成内部的UI节点,但开发者直接打交道的就是函数和参数。
关于Modifier的认知模型,你可以这么记:
Modifier(大写)是约束工厂,用来创建一条全新的约束链的起点。modifier(小写)是传递过来的约束链实例,每个Composable可以接收它,然后在链的末尾追加新约束(调用方法返回新实例),再传给子组件或者作为自身的约束使用。- Modifier本质是不可变的约束链表,框架会按顺序执行链上的每个约束,来完成布局、绘制等操作。
你之前猜的Kotlin引用传递是对的,但要注意:虽然modifier是引用传递,但因为Modifier不可变,调用方法不会改原对象,只会生成新对象,所以不会影响上游。
内容的提问来源于stack exchange,提问作者stilllearning

