网站建设的问题疑问,营口化工网站建设,市建设工程信息网,新网站如何做优化前言
“Jetpack Compose 是一个适用于 Android 的新式声明性界面工具包。Compose 提供声明性 API#xff0c;让您可在不以命令方式改变前端视图的情况下呈现应用界面#xff0c;从而使编写和维护应用界面变得更加容易。”
以上是Compose官网中对于Compose这套全新的Androi…前言
“Jetpack Compose 是一个适用于 Android 的新式声明性界面工具包。Compose 提供声明性 API让您可在不以命令方式改变前端视图的情况下呈现应用界面从而使编写和维护应用界面变得更加容易。”
以上是Compose官网中对于Compose这套全新的Android UI库的介绍Compose的到来为Android引入了声明式、响应式的全新开发方式直接以函数调用的形式使用组件取代了原先冗长的Activity定义以及.xml文件编写这一点也是当前TDF团队Kuikly框架同样所具备的能力给予声明式、响应式的特性加速用户开发并且Kuikly直接复用了Android的view体系与Compose以全新的Composable以及Compose树而言一定程度上可以加速新用户对于底层的理解。
Compose执行生命周期
我们继续ComposeCompose在声明式函数的基础上引入了重组的能力结合后续的度量策略Compose UI在发生变化时会被系统的快照系统SnapManager监测到并使用协程管道的方式获取信息然后执行重组动作重组动作会对状态变更的UI元素进行重新渲染而不修改状态未改变的其余UI元素。
Compose程序的执行之后一直到页面渲染出结果以及后续的持续UI变更共可以分为4个阶段分别是“组合 -- 布局 -- 渲染 -- 重组”
组合阶段
“在组合阶段Compose 运行时会执行可组合函数并 输出一个表示界面的树结构。这个界面树由 包含下一阶段所需的所有信息的布局节点”官方文档
因此我们不难理解Compose仍然是采用了树型结构作为UI加载、布局、渲染的底层结构但是有所变更的是如今的Compose树的节点类型为ComposeUiNode在组件树真正开始被载入时会变成LayoutNode类型的节点。LayoutNode是ComposeUiNode的子类其继承了ComposeUiNode中所有组件设置的属性。对应的Row、Image、Column以及Text组件所形成的LayoutNode树显示如下
因此我们可以明确了第一点即组合阶段就是产生所有组件的LayoutNode树为后续布局阶段提供遍历的内容。
结合源码我们梳理了组合阶段的执行流程显示如下 相关源码展示如下setContent中内部的函数调用在此不做展示可以结合流程图去检索源码即可了解其中的调用链。 private object TutorialSnippet1 {class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {Text(Hello world!)}}}}public fun ComponentActivity.setContent(parent: CompositionContext? null,content: Composable () - Unit) {val existingComposeView window.decorView.findViewByIdViewGroup(android.R.id.content).getChildAt(0) as? ComposeViewif (existingComposeView ! null) with(existingComposeView) {setParentCompositionContext(parent)setContent(content)} else ComposeView(this).apply {// Set content and parent **before** setContentView// to have ComposeView create the composition on attachsetParentCompositionContext(parent)setContent(content)// Set the view tree owners before setting the content view so that the inflation process// and attach listeners will see them already presentsetOwners()setContentView(this, DefaultActivityContentLayoutParams)}} 布局阶段
在布局阶段Compose 会使用在组合阶段生成的界面树 作为输入计算每个布局节点在界面树中的测量和放置位置此过程中将遍历每个LayoutNode节点执行子节点测量、自我测量以及放置子节点三个过程。
以上图的LayoutNode节点树为例此过程可描述为 1、Row 测量其子项 Image 和 Column。 2、系统测量了 Image。它没有任何子元素因此它决定自己的 尺寸并将尺寸报告给 Row。 3、接下来测量 Column。它会测量自己的子项两个 Text 可组合项。 4、系统将测量第一个 Text。由于没有任何子元素因此它决定 自己的尺寸并将其尺寸报告给 Column。系统测量第二个 Text。由于没有任何子元素因此它决定 并将其报告给 Column。 5、Column 使用子测量值来确定自己的尺寸。它使用 最大子元素宽度及其子元素高度之和。 6、Column 会相对于自身放置其子项并将其置于子项下方 相互垂直 7、Row 使用子测量值来确定自己的尺寸。它使用 子元素的最大高度及其子元素宽度之和。然后 子项。
采用深度遍历的方式执行LayoutNode树的遍历基于constrains约束树上每个组件所在的位置在遍历完成后都将计算完成即完成布局阶段等待后续的渲染阶段。
而布局阶段中Modifier类已经开始在遍历的时候就被加载并在宽高计算时被认为是待度量的因素。具体各组件的度量策略我附上一张表格。
!!! 目前核心关心的是Modifier属性是怎么被加载的
① 组成Modifier链
Surface(modifier Modifier.size(200.dp) // 设置组件大小.background(Color.LightGray) // 设置背景颜色.offset(x 10.dp, y 20.dp) // 设置偏移量) {Text(text Hello, Jetpack Compose!,fontSize 20.sp,color Color.Black,modifier Modifier.padding(8.dp) // 内部文本的额外内边距)} 以此代码为例Surface组件使用Modifier伴生对象基于链式调用的方式声明了多个属性也正如此Modifier是Compose中修饰 UI 组件的关键数据结构。 interface Modifier {fun R foldIn(initial: R, operation: (R, Element) - R): Rfun R foldOut(initial: R, operation: (Element, R) - R): Rfun any(predicate: (Element) - Boolean): Booleanfun all(predicate: (Element) - Boolean): Booleaninfix fun then(other: Modifier): Modifier ...interface Element : Modifier {...}companion object : Modifier {...}}
Modifier 接口有三个直接实现类或接口伴生对象 Modifier、内部子接口Modifier.Element、CombinedModifier。
伴生对象 Modifier最常用的 Modifier 即在代码中使用 Modifier.xxx()内部子接口 Modifier.Element当我们使用Modifier.xxx()时其内部实际会创建一个Modifier 实例。如使用 Modifier.size(100.dp) 时内部会创建一个 SizeModifier 实例
其背后的继承关系是 而类似LayoutModifier的中间类显示如下不同的中间Modifier.Element子类将使得Modifier链建立时使用CombinedModifier来链接 ② Modifier链的构建过程
then()
size属性定义时建立的SizeModifier实例被当作参数传入 then() 方法中。而这个 then() 方法就是 Modifier 间相互连接的关键方法。 Modifier.size(100.dp)fun Modifier.size(size: Dp) this.then( // 关键方法SizeModifier(...))// 返回待连接的Modifiercompanion object : Modifier {...override infix fun then(other: Modifier): Modifier other}
继续链式调用后续属性BackGround, padding Modifier.size(100.dp).background(Color.Red)fun Modifier.background(color: Color,shape: Shape RectangleShape
) this.then( // 当前 this 指向 SizeModifier 实例Background(...))
而此时Modifier链也将引入新的类型CombinedModifier来链接所对应的中间Modifier.Element子类不一致时的Modifier interface Modifier {infix fun then(other: Modifier): Modifier if (other Modifier) this else CombinedModifier(this, other)}class CombinedModifier(private val outer: Modifier,private val inner: Modifier) : Modifier
形成以下的样式 所有属性全部上链会形成 至此Modifier链已经构建完成而在LayoutNode遍历时会基于nodes属性访问管理Modifier链的Nodechain类 internal val nodes NodeChain(this)
而辅助遍历时的数据结构是
internal val innerCoordinator: NodeCoordinatorget() nodes.innerCoordinatorinternal val layoutDelegate LayoutNodeLayoutDelegate(this) internal val outerCoordinator: NodeCoordinatorget() nodes.outerCoordinator
innerCoordinator是指最内层的协调器直接与LayoutNode关联负责处理Modifier链的内部操作包括处理内部Modifier、管理LayoutNode子LayoutNode协助他们的度量工作以及传递事件
outerCoordinator是指最外层的协调器负责处理Modifier链的外部操作包括处理外部Modifier协调Modifier的调用顺序以及管理LayoutNode父节点
其中内部Modifier和外部Modifier的分辨规则是
内部 Modifier 是指那些主要影响组件的布局和测量的修饰符。这些修饰符通常在LayoutNode的内部进行操作改变组件的尺寸、位置和布局行为。( padding, size, fillMaxWidth / fillMaxHeight, wrapContentSize, aspectRatio, weight)外部 Modifier 是指那些主要影响组件的绘制和偏移的修饰符。这些修饰符通常在LayoutNode的外部进行操作改变组件的外观、透明度和位置偏移等。( background, border, offset, alpha, clip, shadow);
而其中访问Modifier链的过程将基于foldin与foldout方法取到Modifier上所有的设置信息从而将外部 or 内部 属性的定义值反馈到当前LayoutNode的width, height上并最后在父节点的constrains限制下输出最大的width和height fun R foldIn(initial: R, operation: (R, Element) - R): R
// foldIn() 正向遍历 Modifier 链SizeModifier- Background - PaddingModifierfun R foldOut(initial: R, operation: (Element, R) - R): R
// foldOut() 反向遍历 Modifier 链, PaddingModifier - Background -SizeModifier
绘制阶段
绘制代码期间的状态读取会影响绘制阶段。常见示例包括 Canvas()、Modifier.drawBehind 和 Modifier.drawWithContent。 Modifier知识补充
Compose UI组件 Modifier子类 类图 Compose 常用UI组件 LayoutNode、Modifier、MeasurePolicy汇总