Jetpack Compose-修饰符顺序

问题描述

文档说,修饰语是从左侧添加的。 但是从此示例看来,它们似乎是从右侧应用的: 首先是边框,然后是填充,因为文本和边框之间没有空格

Text("Hi there!",Modifier.padding(10.dp).border(2.dp,Color.magenta))

enter image description here

解决方法

Layouts in Jetpack Compose 代码实验室包含解释修饰符顺序的 Layout modifiers under the hood 步骤,请参阅“顺序很重要” 部分。

当链接修饰符时,顺序很重要,因为它们被应用到它们从早到晚修改的组合物,这意味着左侧修饰符的测量和布局将影响右侧的修饰符。可组合的最终大小取决于作为参数传递的所有修饰符。首先,修饰符会从左到右更新约束,然后,它们返回从右到左的大小

为了更好地理解它,我建议您弄清楚 layouts 在 Compose 中的工作原理。简而言之,padding() 是一个 LayoutModifer,它接受​​一些约束,根据该约束的投影测量其子级大小,并将子级放置在某些坐标处。

让我们看一个例子:

Box(
  modifier = Modifier
    .border(1.dp,Color.Red)
    .size(32.dp)
    .padding(8.dp)
    .border(1.dp,Color.Blue)
)

结果:

enter image description here

但是让我们交换 .size().padding()

Box(
  modifier = Modifier
    .border(1.dp,Color.Red)
    .padding(8.dp)
    .size(32.dp)
    .border(1.dp,Color.Blue)
)

现在我们有了不同的结果:

enter image description here

我希望这个示例可以帮助您了解如何应用修饰符。

人们可以预期红色边框应该是最靠近框的,因为它是最先添加的,所以顺序可能看起来颠倒了,但这样的顺序也有优点。我们来看看这个可组合的:

@Composable
fun MyFancyButton(modifier: Modifier = Modifier) {
  Text(
    text = "Ok",modifier = modifier
      .clickable(onClick = { /*do something*/ })
      .background(Color.Blue,RoundedCornerShape(4.dp))
      .padding(8.dp)
  )
}

只需将 modifier 移动到参数,可组合项就允许其父项添加额外的修饰符,例如额外的边距。因为最后添加的修饰符离按钮最近,所以边框和内边距不会受到影响。

,
  • 在Android Compose中,结果图像是从外层向中间的Composable构造的。 这意味着第一个定义的绿色边框是外部边界,最后一个定义的红色边框是内部边界。 这非常令人困惑,因为在结果中距离代码中最接近文本可组合的绿色修饰符距离它最远。
  • 这与SwiftUI相反,在SwiftUI中,修饰符在代码和生成的Image中以相同顺序出现。 在代码中最接近Composable的修饰符在生成的图像中也最接近它。
  • 如果您想想象生成的Image是从Composable所处的中心构建的(就像在SwiftUI中一样),那么修饰符将以与给出的相反顺序应用(从下至上)。
  • 因此,如果您的文本可与两个边框修饰符一起使用
    • 距离代码中可撰写文本最远的边框修饰符(底部红色)
    • 将最接近结果图像中的“可组合文字”
  • 修饰符从外层向内层应用
    • 将.border(2.dp,Color.Green)应用到最外层
    • 向内应用.padding(50.dp)
    • 将.border(2.dp,Color.Red)应用到最内层
package com.example.myapplication

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.setContent
import androidx.compose.ui.unit.dp

class MainActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      Text("Hi there!",Modifier
          .border(2.dp,Color.Green)
          .padding(50.dp)
          .border(2.dp,Color.Red)
      )
    }
  }
}

enter image description here

,

在这种情况下,第一次填充类似于元素的边距。

比较这些Composables,您将看到不同之处。

@Composable
fun Example() {
    // Default
    Box(modifier = Modifier.background(Color.Cyan),alignment = Alignment.Center){
        Text("Hi there!",Modifier.border(2.dp,Color.Magenta))
    }
    Divider()
    // 10dp margin
    Box(modifier = Modifier.background(Color.Cyan),Modifier.padding(10.dp).border(2.dp,Color.Magenta))
    }
    Divider()
    // 10dp margin and 10dp padding
    Box(modifier = Modifier.background(Color.Cyan),Color.Magenta).padding(10.dp))
    }
}

Render of given Example

,

“修饰符元素可以使用然后进行组合。顺序很重要;首先出现的修饰符元素将首先应用。” @ {here

它首先应用于具有填充10.dp的外层,然后应用于具有color.Magenta的边框,依此类推(“从左到右”)。 80.dp填充最后应用于内层。

@Composable
fun test() {
    Text("Hi there!",Modifier.background(color = Color.Green)
                    .padding(10.dp)
                    .border(2.dp,Color.Magenta)
                    .padding(30.dp)
                    .border(2.dp,Color.Red)
                    .padding(80.dp)
    )
}

enter image description here