Arc*_*nes 23 android android-jetpack-compose
什么时候Modifier.composed { ... }有用?Modifier.padding()如果我可以简单地重来一遍,为什么我需要它Modifier.composed { PaddingModifier(...) }?
adn*_*eal 24
注意 -composed不再是创建 Composition-aware 的推荐方法Modifier。现在建议Modifier像任何其他可组合项一样创建组合感知:
@Composable
fun Modifier.composableModifier(): Modifier {
val color = LocalContentColor.current.copy(alpha = 0.5f)
return this then Modifier.background(color)
}
@Composable
fun MyComposable() {
val composedModifier = Modifier.composableModifier()
}
Run Code Online (Sandbox Code Playgroud)
查看有关创建自定义的最新文档Modifier以获取更多信息:
https ://developer.android.com/jetpack/compose/custom-modifiers
Modifier.composed允许创建一个组合感知的修改器工厂,这对于具体化特定于实例的有状态修改器非常有用。来自文档:
声明一个 Modifier 的即时组合,该组合将针对它修改的每个元素进行组合。composed 可用于实现有状态修饰符,这些修饰符为每个被修改的元素具有特定于实例的状态,允许相同的修饰符实例安全地重用于多个元素,同时维护特定于元素的状态。
换句话说,它允许您将提升的状态注入特定于元素的状态Modifier并使用remember、DisposableEffect、Ambient等。例如:
fun Modifier.fancyModifier(
enabled: Boolean = false,
onClick: () -> Unit = {}
) = composed(inspectorInfo = debugInspectorInfo {
name = "fancyModifier"
value = enabled
}) {
var paddingValue by remember { mutableStateOf(0.dp) }
onCommit(enabled) {
paddingValue = if (enabled) 16.dp else 0.dp
}
fillMaxWidth()
.clickable { onClick() }
.padding(paddingValue)
}
Run Code Online (Sandbox Code Playgroud)
LazyColumnFor(items = List(size = 10) { "$it" }) {
var enabled by remember { mutableStateOf(false) }
Text(
text = "fancy modifier",
modifier = Modifier.fancyModifier(enabled) {
enabled = !enabled
}
)
}
Run Code Online (Sandbox Code Playgroud)
您还可以InspectorInfo使用 来声明以帮助调试debugInspectorInfo。来自文档:
如果指定了spectorInfo,则该修饰符将在开发过程中对工具可见。指定原始修饰符的名称和参数。以及可选地声明
InspectorInfo以帮助调试。
如果您有超过您想要跟踪的值,properties则可以使用该字段。value
注意:debugInspectorInfo lambda 已从release构建中删除。
class FancyModifierTest {
@Before
fun setup() {
isDebugInspectorInfoEnabled = true
}
@After
fun teardown() {
isDebugInspectorInfoEnabled = false
}
@Test
fun testFancyModifierInspectableValue() {
val modifier = Modifier.fancyModifier() as InspectableValue
assertEquals(modifier.nameFallback, "fancyModifier")
assertEquals(modifier.valueOverride, false)
assertEquals(modifier.inspectableElements.toList().size, 0)
}
}
Run Code Online (Sandbox Code Playgroud)
下面是一些更实际的例子:
您可以使用它存储内存繁重的对象,这样每次为特定元素调用该修饰符时就不会实例化。
这个组合会记住带有索引的颜色,因此每次重新组合后它都会返回最初随机创建的颜色。
// Creates stateful modifier with multiple arguments
fun Modifier.composedBackground(width: Dp, height: Dp, index: Int) = composed(
// pass inspector information for debug
inspectorInfo = debugInspectorInfo {
// name should match the name of the modifier
name = "myModifier"
// add name and value of each argument
properties["width"] = width
properties["height"] = height
properties["index"] = index
},
// pass your modifier implementation that resolved per modified element
factory = {
val density = LocalDensity.current
val color: Color = remember(index) {
Color(
red = Random.nextInt(256),
green = Random.nextInt(256),
blue = Random.nextInt(256),
alpha = 255
)
}
// add your modifier implementation here
Modifier.drawBehind {
val widthInPx = with(density) { width.toPx() }
val heightInPx = with(density) { height.toPx() }
drawRect(color = color, topLeft = Offset.Zero, size = Size(widthInPx, heightInPx))
}
}
)
Run Code Online (Sandbox Code Playgroud)
每次可组合项重新组合时都会创建一种颜色
fun Modifier.nonComposedBackground(width: Dp, height: Dp) = this.then(
// add your modifier implementation here
Modifier.drawBehind {
// Without remember this color is created every time item using this modifier composed
val color: Color = Color(
red = Random.nextInt(256),
green = Random.nextInt(256),
blue = Random.nextInt(256),
alpha = 255
)
val widthInPx = width.toPx()
val heightInPx = height.toPx()
drawRect(color = color, topLeft = Offset.Zero, size = Size(widthInPx, heightInPx))
}
)
Run Code Online (Sandbox Code Playgroud)
用法
var counter by remember { mutableStateOf(0) }
Button(
onClick = { counter++ },
modifier = Modifier.fillMaxWidth()
) {
Text(text = "Increase $counter")
}
TutorialText2(text = "Modifier.composed")
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Box(
modifier = Modifier
.composedBackground(150.dp, 20.dp, 0)
.width(150.dp)
) {
Text(text = "Recomposed $counter")
}
Box(
modifier = Modifier
.composedBackground(150.dp, 20.dp, 1)
.width(150.dp)
) {
Text(text = "Recomposed $counter")
}
}
TutorialText2(text = "Modifier that is not composed")
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Box(
modifier = Modifier
.nonComposedBackground(150.dp, 20.dp)
.width(150.dp)
) {
Text(text = "Recomposed $counter")
}
Box(
modifier = Modifier
.nonComposedBackground(150.dp, 20.dp)
.width(150.dp)
) {
Text(text = "Recomposed $counter")
}
}
Run Code Online (Sandbox Code Playgroud)
结果
另外,在实践中,您可以创建一个动画抖动修改器,例如
fun Modifier.shake(enabled: Boolean) = composed(
factory = {
val scale by animateFloatAsState(
targetValue = if (enabled) .9f else 1f,
animationSpec = repeatable(
iterations = 5,
animation = tween(durationMillis = 50, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
)
)
Modifier.graphicsLayer {
scaleX = if (enabled) scale else 1f
scaleY = if (enabled) scale else 1f
}
},
inspectorInfo = debugInspectorInfo {
name = "shake"
properties["enabled"] = enabled
}
)
Run Code Online (Sandbox Code Playgroud)
用法
Icon(
imageVector = Icons.Default.NotificationsActive,
contentDescription = null,
tint = Color.White,
modifier = Modifier
.shake(enabled)
.background(Color.Red, CircleShape)
.size(50.dp)
.padding(10.dp)
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8993 次 |
| 最近记录: |