【问题标题】:Create custom Modifier element in Compose在 Compose 中创建自定义修饰符元素
【发布时间】:2022-01-23 02:40:23
【问题描述】:

根据 Compose 的文档,我们可以添加自定义 Modifier 类,如下所示:

class SpacingModifier(val space: Dp) : Modifier.Element
fun Modifier.innerSpacing(space: Dp) = this.then(SpacingModifier(space))

@Composable
fun MyListOfItems(
  list: List<Model>,
  modifier: Modifier = Modifier
) {
  LazyColumn(modifier = modifier) {
    items(list) { model ->
      ViewHolder(model)
      Spacer(modifier = Modifier.height(/*I need the innerSpacing value here*/))
    }
  }
}

@Preview(showBackground = true)
@Composable
fun PreviewList() {
  MyListOfItems(
    list = listOf(
      Model(text = "Hello 1", checked = true),
      Model(text = "Hello 2", checked = false),
      Model(text = "Hello 3", checked = true),
      Model(text = "Hello 4", checked = true),
      Model(text = "Hello 5", checked = false)
    ),
    modifier = Modifier
      .background(Color.Red)
      .innerSpacing(16.dp) // <- My extension function here
  )
}

如果我有能力为修饰符声明扩展函数,我如何在上面示例中的可组合内访问它?

【问题讨论】:

  • 我这里有一篇文章展示了如何创建自定义修饰符:fvilarino.medium.com/…
  • 为什么不直接将innerSpace 作为参数传递给MyListOfItems
  • 因为在现实中,有大约 5-10 个参数与我的可组合配置相关,我希望它们与修饰符属性链接。即使出于普遍的好奇心,谷歌也提供了这样一个代码 sn-p 作为Modifier 上的第一件事。我们如何检索属性?
  • 查看anyallfoldInfoldOut,它们允许您从Modifier 中提取信息。

标签: android kotlin android-jetpack-compose


【解决方案1】:

Modifier 是一个有序的、不可变的修饰符元素集合,用于为 Compose UI 元素装饰或添加行为。例如,背景、填充和点击事件侦听器装饰或添加行为到行、文本或按钮。

修饰符不能由您的可组合函数直接解释,而是Layout 是大多数可组合函数的根,例如RowColumnBoxSubcomposeLayout,它是LazyColumn 的父级、LazyRowBoxWithConstraints

@Composable inline fun Layout(
    content: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    measurePolicy: MeasurePolicy
) {
    val density = LocalDensity.current
    val layoutDirection = LocalLayoutDirection.current
    val viewConfiguration = LocalViewConfiguration.current
    ReusableComposeNode<ComposeUiNode, Applier<Any>>(
        factory = ComposeUiNode.Constructor,
        update = {
            set(measurePolicy, ComposeUiNode.SetMeasurePolicy)
            set(density, ComposeUiNode.SetDensity)
            set(layoutDirection, ComposeUiNode.SetLayoutDirection)
            set(viewConfiguration, ComposeUiNode.SetViewConfiguration)
        },
        skippableUpdate = materializerOf(modifier),
        content = content
    )
}

@Composable
fun SubcomposeLayout(
    modifier: Modifier = Modifier,
    measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult
) {
    SubcomposeLayout(
        state = remember { SubcomposeLayoutState() },
        modifier = modifier,
        measurePolicy = measurePolicy
    )
}

您可以链接您的修饰符,例如

private fun Modifier.getBadgeModifier(
    badgeState: BadgeState,
    shape: Shape
) = this
    .materialShadow(badgeState = badgeState)
    .then(
        badgeState.borderStroke?.let { borderStroke ->
            this.border(borderStroke, shape = shape)
        } ?: this
    )
    .background(
        badgeState.backgroundColor,
        shape = shape
    )

Modifier.materialShadow 也是一个 Modifier,它被链接起来以基于一个名为 badgeState 的类绘制阴影,该类包含形状、阴影等。

class BadgeState(
    var maxNumber: Int = 99,
    var circleShapeThreshold: Int = 1,
    @IntRange(from = 0, to = 99) var roundedRadiusPercent: Int = 50,
    backgroundColor: Color,
    var horizontalPadding: Dp = 4.dp,
    var verticalPadding: Dp = 0.dp,
    textColor: Color,
    var fontSize: TextUnit,
    var fontWeight: FontWeight? = null,
    var fontFamily: FontFamily? = null,
    var fontStyle: FontStyle? = null,
    var textDecoration: TextDecoration? = null,
    var shadow: MaterialShadow? = null,
    var borderStroke: BorderStroke? = null,
    showBadgeThreshold: Int = Int.MIN_VALUE,
)

此外,当您需要向 Composable 函数添加多个参数或访问这些参数时,您可以像 Text Composable 使用 TextStyle 那样进行操作

   @Composable
    fun Text(
        text: String,
        modifier: Modifier = Modifier,
        // Other properties
        style: TextStyle = LocalTextStyle.current
    ) 

    class TextStyle(
        val color: Color = Color.Unspecified,
        val fontSize: TextUnit = TextUnit.Unspecified,
        val fontWeight: FontWeight? = null,
        val fontStyle: FontStyle? = null,
        val fontSynthesis: FontSynthesis? = null,
        val fontFamily: FontFamily? = null,
        val fontFeatureSettings: String? = null,
        val letterSpacing: TextUnit = TextUnit.Unspecified,
        val baselineShift: BaselineShift? = null,
        val textGeometricTransform: TextGeometricTransform? = null,
        val localeList: LocaleList? = null,
        val background: Color = Color.Unspecified,
        val textDecoration: TextDecoration? = null,
        val shadow: Shadow? = null,
        val textAlign: TextAlign? = null,
        val textDirection: TextDirection? = null,
        val lineHeight: TextUnit = TextUnit.Unspecified,
        val textIndent: TextIndent? = null
    )

【讨论】:

    【解决方案2】:

    如果您需要 LazyColumnLazyRow 中的子项的内间距,则应使用 verticalArrangement = modifier.spacedBy(..)horizontalArrangement = modifier.spacedBy(...)

    【讨论】:

      猜你喜欢
      • 2013-04-10
      • 2017-07-19
      • 2021-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-03
      • 2021-11-21
      • 1970-01-01
      相关资源
      最近更新 更多