引言:Compose视图是如何构成的,如何运行在传统的View上的呢
Compose ui是由视图树组成,树是由LayoutNode构成,Composable最终统一由CompseView进行管理,ComposeView是连接传统View和Compose的桥梁。通过布局查看器查看布局结构如下
接下来一次介绍它们
什么是AbstractComposeView
它有三个子类ComposeView、DialogLayout、PopupLayout子类,分别对应Android下Activity、Dialog、Popup的window窗口,它是对Android系统下的各类窗口进行适配,并生成对应的Compose。
ComposeView它又是什么 (ViewGroup)
它继承自AbstractComposeView,负责对Android平台的Activity的窗口进行适配;
1、ComposeView接入传统的View视图后,内部的ui都在Compose内部完成,来自AndroidComposeView的绘制,测量布局、手势事件分发都是下沉到LayoutNode去完成
class ComposeView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AbstractComposeView(context, attrs, defStyleAttr) {}
AndroidComposeView作用
它是ComposeView唯一的子节点,它也是一个ViewGroup,也是LayoutNode视图树的持有者它的结构如下
internal class AndroidComposeView(
context: Context,
override val coroutineContext: CoroutineContext
) : ViewGroup(context), Owner, ViewRootForTest, PositionCalculator, DefaultLifecycleObserver {
override val root = LayoutNode().also {
it.measurePolicy = RootMeasurePolicy
it.density = density
// Composed modifiers cannot be added here directly
it.modifier = Modifier
.then(semanticsModifier)
.then(rotaryInputModifier)
.then(focusOwner.modifier)
.then(keyInputModifier)
.then(dragAndDropModifierOnDragListener.modifier)
}
//...
override fun onResume(owner: LifecycleOwner) {}
override fun onAttach(node: LayoutNode) {}
override fun onDetach(node: LayoutNode) {}
override fun dispatchKeyEvent(event: AndroidKeyEvent): Boolean {}
//...
}
AndroidComposeView它的创建过程
1、在Activity中的onCreate方法中调用ComposeActivity的拓展函数setContent方法
public fun ComponentActivity.setContent(
parent: CompositionContext? = null,
content: @Composable () -> Unit
) {
val existingComposeView = window.decorView
.findViewById<ViewGroup>(android.R.id.content)
.getChildAt(0) as? ComposeView
if (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 attach
setParentCompositionContext(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 present
setOwners()
setContentView(this, DefaultActivityContentLayoutParams)
}
}
2、然后调用ComposeView中的setContent方法创建AndroidComposeView视图,调用细节如下
1、setContent方法调用ComposeView父类AbstractComposeView 中的createComposition方法
2、调用AbstractComposeView 中的ensureCompositionCreated方法,方法内调用
3、调用AbstractComposeView 中的setContent方法创建AndroidComposeView
//ComposeView源码如下
class ComposeView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AbstractComposeView(context, attrs, defStyleAttr) {
//...
fun setContent(content: @Composable () -> Unit) {
shouldCreateCompositionOnAttachedToWindow = true
this.content.value = content
if (isAttachedToWindow) {
createComposition()
}
}
}
//调用AbstractComposeView 中的createComposition方法
fun createComposition() {
check(parentContext != null || isAttachedToWindow) {
"createComposition requires either a parent reference or the View to be attached" +
"to a window. Attach the View or call setParentCompositionReference."
}
ensureCompositionCreated()
}
//调用AbstractComposeView 中的ensureCompositionCreated方法
private fun ensureCompositionCreated() {
if (composition == null) {
try {
creatingComposition = true
//调用AbstractComposeView 中的setContent方法创建AndroidComposeView
composition = setContent(resolveParentCompositionContext()) {
Content()
}
} finally {
creatingComposition = false
}
}
}
internal fun AbstractComposeView.setContent(
parent: CompositionContext,
content: @Composable () -> Unit
): Composition {
GlobalSnapshotManager.ensureStarted()
val composeView =
if (childCount > 0) {
getChildAt(0) as? AndroidComposeView
} else {
removeAllViews(); null
} ?: AndroidComposeView(context, parent.effectCoroutineContext).also {
addView(it.view, DefaultLayoutParams)
}
return doSetContent(composeView, parent, content)
}
Compose模块划分
1、在开发阶段:Studio提供静态代码检测,和ui的实时预览
2、编译阶段:Compose plugin 会对@Composable注解进行预处理,通过代码插入提高编码效率
3、在运行阶段:Compose被分为了四层,从上至下依次为:
Material:基于Material design系统实现各种的Composable、主题、图标,如果app遵循Material design设计,则使用该层进行构建
Foundation:提供基础的Compsable,例如Row、Columun、LazyColumn等布局ui,以及特定的手势识别等通用功能
UI:包含很多功能,例如ui-text、ui-tooling等,构成了上层Compsable运行的基础,例如Compsable的测量、布局、绘制、事件、Modifier管理
Runtime:核心模块,Compose是通过ui树进的diff驱动洁面刷新的,此模块提供了基本的ui树的管理能力,如果只需要树的管理能力,不需要ui,则可以在此层进行构建
------笔记 End------