# Ahoy **Repository Path**: brokerxu/ahoy ## Basic Information - **Project Name**: Ahoy - **Description**: compose项目 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-09-16 - **Last Updated**: 2025-11-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README compose学习 //新值的应用通知 snapshot.readObserver //只有发生组合过程中,才会执行writeObserver snapshot.writeObserver val text = mutableStatOf("1") setContent{ Box(modifier = Modifier.clickable{ text.value = "2" //这里不会执行到“snapshot.writeObserver”,因为这个过程不是在compose组合过程中执行的 }){ Text(test.value) test.value = "3"//这个过程是compose组合过程中发生的,所以会使 “Text(test.value)”的赋值失效,会触发“snapshot.writeObserver”,所以通知下一帧刷新 } } get()是标记读 set()是标记失效 remember 使用 1、拿到对象的最新值 2、可以防止recompose,被反复执行导致的值出错 3、起到缓存作用,防止重复初始化 //这个类是不可靠的 class User(var name:String){ } //这个类是可靠的 class User(val name:String){ } @Stable/@Immutable 保证被修饰的类被标记为可靠的类,compose重新组合时,就不会被重复执行 -现在相等就永远相等 -当公开属性改变的时候,通知到用到这个属性的Composition -公开属性需要全部是稳定的、可靠属性。 //这种情况也可以不用标记@Stable也可以保证类的可靠 class User(name:String){ val name by mutableStateOf(name) } compositionLocal compose函数中使用局部变量 CompositionLocalProvider 局部变量穿透能力 + 重组触发条件(Recompose) - 状态变化 - 组合函数调用 - 父组件重组 - 快照读取 + compositionLocal //包裹范围内的组件都可以使用compositionLocal定义的变量 setContent { CompositionLocalProvider(LocalBackground provides Color.Red) { Text(text = "Hello World",modifier = Modifier.background(LocalBackground.current)) } } val LocalBackground = compositionLocalOf{Color.GREEN} + modifier 创建是通过工厂函数创建 + modifier.then() 组合其他的modifier使用 + modifier.all() 和这个modifier相同,或者完全不包含就返回true + modifier.any() 包含这个modifier,返回true + modifier.foldOut() + modifier.foldIn() + Modifier.composed() 创建代码有状态的modifier Modifier.composed{ //组合时才会调用这里 } //可以用在自定义modifier中 fun Modifier.noRippleClickable(enabled:Boolean = true,onClick: () -> Unit) = composed{ val interactionSource = remember { MutableInteractionSource() } this.clickable( interactionSource = interactionSource, indication = null, enabled = enabled, onClick = onClick ) } + modifier.layout() 修改控件的尺寸和位置;无法操作内部子控件 modifier.layout{measurable, constraints -> } - measurable:是Measurable接口的实现,其中measure方法进行裁量; measurable,如果控件是最内层的情况,measurable其实就是InnerLayoutNodeWrapper;如果控件中包裹了其他控件,那么measurable就是ModifiedLayoutNode - constraints:包含宽度和高度的上下限 Text("1111111", Modifier.layout { measurable, constraints -> //测量宽高 val placeable = measurable.measure(constraints) //对控件进行尺寸保存和位置更改 layout(placeable.width,placeable.h eight){ //对控件进行偏移 placeable.placeRelative(0,0) } }) + LayoutNode => remeasure(performMeasure:真正做测量的 ) -> replace 实例: Text("11111", Modifier.padding(10.dp).padding(20.dp)) Box(Modifier.padding(10.dp).padding(20.dp)) [LayoutModifier - 10.dp ModifiedLayoutNode [LayoutModifier -20.dp ModifiedLayoutNode 实际组件 Text(),Box() innerLayoutNodeWrapper - InnerPlaceable ] ] 其实最终padding是30 + DrawModifier 绘制 Modifier.then(object:DrawModifier{ override fun ContentDrawScope.draw(){ 绘制1 drawContent()//原有的绘制,不写的话,原有的绘制(drawWithContent右边调用的modifier)就会丢弃 绘制2 } }) 是等价的 Modifier.drawWithContent{ 绘制1 drawContent()//原有的绘制,不写的话,原有的绘制(drawWithContent右边调用的modifier)就会丢弃 绘制2 } DrawModifier都会被包进LayoutNode中的Modifier中 + pointerInputModifier Modifier.clickable{ //点击事件 } Box(Modifier.padding(20.dp).background(Color.Gray).size(40.dp).combinedClickable(onLongClick = { //长按 }, onDoubleClick = { //双击 }, onClick = { //单击 })){ } Modifier.pointerInput(Unit) { awaitPointerEventScope { //事件监听 } } Modifier.pointerInput(Unit){ //点击 detectTapGestures(onTap = {}, onDoubleTap = {}, onPress = {}, onLongPress = {}) //拖拽 detectDragGestures(onDragStart = { },onDragEnd = { },onDragCancel = { },onDrag = {change: PointerInputChange, dragAmount: Offset -> }) }){ } + ParentDataModifier ParentDataModifierElement ParentDataModifierNode ParentDataModifier:父组件需要子组件所提供的一些信息时,才会用到ParentDataModifier - weight //weight就是一个ParentDataModifier的实现 Modifier.layoutId("")//在自定义布局中用,给子组件设置,用于父组件进行判断测量 Text("1111111", Modifier.layout { measurable, constraints -> measurable.forEach{ when(it.layoutId){ "big" ->it.measure()//按照big的方式去测量 "small" ->it.measure()//按照small的方式去测量 else -> it.measure() } } }) //ParentDataModifier -- 自定义属性 @Composable fun CustomLayout(modifier: Modifier = Modifier,content:@Composable () -> Unit){ Layout(content,modifier,object : MeasurePolicy{ override fun MeasureScope.measure( measurables: List, constraints: Constraints ): MeasureResult { measurables.forEach { //拿到子组件的数据 val data = it.parentData as? Layout2Data } return layout(100, 100, placementBlock = { }) } }) } class Layout2Data(var weight: Float = 0f,var big: Boolean = false) fun Modifier.bigData(big: Boolean) = then(object : ParentDataModifier{ override fun Density.modifyParentData(parentData: Any?): Any? { //数据融合,之前设置的被覆盖 return ((parentData as? Layout2Data) ?: Layout2Data()).also { it.big = big } } }) fun Modifier.weightData(weight: Float) = then(object : ParentDataModifier{ override fun Density.modifyParentData(parentData: Any?): Any? { //数据融合,之前设置的被覆盖 return ((parentData as? Layout2Data) ?: Layout2Data()).also { it.weight = weight} } }) @Preview @Composable fun testClick2(){ CustomLayout(Modifier.size(200.dp)) { Text("", Modifier.bigData(true).weightData(1f)) Text("", Modifier.bigData(false).weightData(1f)) Text("", Modifier.bigData(false).weightData(1f)) } } + SemanticsModifier 语义树 ----无障碍场景和开发测试 是用于增强组件可访问性(Accessibility)的核心修饰符,它允许开发者为 UI 元素添加语义信息,帮助辅助技术(如屏幕阅读器 TalkBack)正确解读和交互 UI 内容。 核心作用 为无默认语义的自定义组件添加描述信息 覆盖或扩展系统默认的语义属性 构建组件之间的逻辑关系(如父子关系、选中状态等) 支持辅助技术的交互操作(如点击、选择等) semantics(true):会合并子父免打扰语义 semantics(false):不会合并子父免打扰语义 Text( text = "提交", modifier = Modifier .semantics(true) { // 添加内容描述 contentDescription = "确认提交表单的按钮" // 标记为可点击 onClick { true } // 返回true表示消费点击事件 } .clickable { /* 点击逻辑 */ } ) clearAndSetSemantics:擦除子组件的免打扰语义 Text("", Modifier.bigData(true).clearAndSetSemantics(){})