android Jetpack合成-修改器顺序

uplii1fm  于 2023-02-20  发布在  Android
关注(0)|答案(5)|浏览(190)

文档中说修饰符是从左边应用的,但是从这个例子看起来它们是从右边应用的:首先是边框,然后是填充,因为文本和边框之间没有空格

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

y53ybaqx

y53ybaqx1#

Layouts in Jetpack Compose codelab包含引擎盖步骤下的布局修改器,该步骤解释了修改器顺序,请参见 "顺序问题" 部分。
在链接修饰符时,顺序很重要,因为修饰符是从早到晚应用于它们修改的可组合对象的,这意味着左侧修饰符的度量和布局将影响右侧的修饰符。可组合对象的最终大小取决于作为参数传递的所有修饰符。首先,修饰符将从左到右更新约束,然后,它们从右向左返回大小
为了更好地理解它,我建议你弄清楚layouts在Compose中是如何工作的。简而言之,padding()是一个LayoutModifer,它接受一些约束,根据这些约束的投影测量其子元素的大小,并将子元素放置在一些坐标上。
让我们看一个例子:

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

结果是:

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

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

现在我们得到了不同的结果:

我希望这个例子能帮助你弄清楚如何应用修饰符。
我们可以预期红色边框应该是最靠近方框的,因为它是第一个添加的,所以顺序可能看起来相反,但这样的顺序也有优点。

@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移动到参数中,组合对象就允许其父对象添加额外的修饰符,如额外边距,因为最后添加的修饰符离按钮最近,所以边框和内部填充不会受到影响。

lh80um4z

lh80um4z2#

  • 在Android Compose中,生成的图像是从外层向中间的Composable构建的。这意味着第一个定义的绿色边框是外边框,最后一个定义的红色边框是内边框。这非常容易混淆,因为代码中最接近文本Composable的绿色修饰符在结果中离它最远。
  • 这与SwiftUI相反,SwiftUI中修饰符在代码和结果图像中以相同的顺序出现。代码中最接近可组合对象的修饰符在结果图像中也最接近可组合对象。
  • 如果你想想象生成的图像是从Composable所在的中心构建的(如SwiftUI中),那么修饰符将以与给定顺序相反的顺序(从下向上)应用。
  • 如果你有两个边框修饰符的文本合成
  • 代码中距离可组合文本最远的border修饰符(底部红色的修饰符)
  • 将最接近结果图像中的文本可组合
  • 从外层向内层应用修饰符
  • 将.border(2.dp,Color.绿色)应用于最外层
  • 向内应用.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)
      )
    }
  }
}

xpszyzbs

xpszyzbs3#

在本例中,第一个填充类似于元素的边距。
比较这些可合成对象,您将看到差异。

@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), alignment = Alignment.Center){
        Text("Hi there!", Modifier.padding(10.dp).border(2.dp, Color.Magenta))
    }
    Divider()
    // 10dp margin and 10dp padding
    Box(modifier = Modifier.background(Color.Cyan), alignment = Alignment.Center){
        Text("Hi there!", Modifier.padding(10.dp).border(2.dp, Color.Magenta).padding(10.dp))
    }
}

5jdjgkvh

5jdjgkvh4#

“修饰符元素可以用then组合。顺序很重要;首先出现的修饰符元素将首先应用。”@here
它首先应用于外层,填充为10.dp,然后应用于边框,颜色为洋红色,依此类推(“从左到右”)。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)
    )
}

k4ymrczo

k4ymrczo5#

修饰符允许我们自定义可组合对象的外观。使用它,您可以:

  • 更改可组合对象的外观、大小、偏移量、填充或边距
  • 添加交互,例如使元素可单击、可滚动、可拖动或可缩放
  • 更改其规模,在屏幕上的位置,而其布局完全不同的地方,或形状,改变其触摸区域。

根据您放置这些修饰符的顺序,您的可组合程序的视觉和行为结构将被塑造。
大多数修饰符都是从上到下或从左到右应用的,一个例外是Modifier.pointerInput(),它默认从右到左或从下到上应用。

修饰符.padding()

Jetpack合成中的Modifier.padding()根据顺序充当填充或边距。
Modifier.padding(10.dp).size(200.dp)在设置大小之前添加空间,您有一个大小为200.dp的可组合文件
Modifier.size(200.dp).padding(10.dp)在每侧设置10.dp填充后添加宽度和高度为180.dp的填充

Box(
    Modifier
        .border(2.dp, Color.Green)
        .padding(10.dp)
        .border(2.dp, Color.Red)
        .size(200.dp)
)

Box(
    Modifier
        .border(2.dp, Color.Cyan)
        .size(200.dp)
        .padding(10.dp)
        .border(2.dp, Color.Magenta)
)

并且填充修饰符是累积的。Modifier.padding(20.dp).padding(20.dp)的总和为40.dp。

Box(
    Modifier
        .border(2.dp, Color.Green)
        .padding(20.dp)
        .border(2.dp, Color.Red)
        .size(200.dp)
)

Box(
    Modifier
        .border(2.dp, Color.Green)
        .padding(20.dp)
        .padding(20.dp)
        .border(2.dp, Color.Red)
        .size(200.dp)
)

修饰符.shadow()

另一个修饰符,根据应用顺序更改组合的外观。对于要应用于组合外部的阴影,它应该在背景或其他修饰符之前应用。如果在Modifier.background之后应用,则可以使用外部阴影。

Box(
    Modifier
        .shadow(5.dp, RoundedCornerShape(8.dp))
        .background(Color.White)
        .size(100.dp)
)

Box(
    Modifier
        .background(Color.White)
        .size(100.dp)
        .shadow(5.dp, RoundedCornerShape(8.dp))
)

修改器.clip()

这个修改器也会根据它的放置顺序来剪切修改器。如果你把它放在Modifier.clickable{}之前,你可以改变或剪切可组合对象的可点击区域。使用这个修改器和Shape可以创建圆形、三角形或菱形圆形区域或创建之前/之后的布局。
这是Modifier.graphicsLayer{}的引擎盖下,你可以查看我的详细答案hereherehere.它可以帮助你创建复杂的布局使用比例,形状,剪辑,平移,和其他很酷的属性。

修饰符偏移量()

这个修饰符对于在布局后改变组合体的位置很有用,不像修饰符。填充改变这个修饰符的值不会改变组合体相对于它的兄弟组合体的位置。但是,根据你设置修饰符.offset的位置,你可以改变组合体的触摸区域,它有两个变体。一个接受lambda的变体推迟状态读取,这是谷歌建议的,而不是接受值的变体。
我使用了一个带值的示例。您可以看到偏移量是否是第一个应用的修饰符,该修饰符在滑块更改值时跟随偏移量移动。在第二个示例中,组合的触摸区域没有更改,因为Modifier.clickable{}Modifier.offset{}之前应用

var offset by remember {
    mutableStateOf(0f)
}
Box(
    Modifier
        .offset(x = offset.dp)
        .clickable {}
        .background(Color.Red)
        .size(100.dp)
)

Box(
    Modifier
        .clickable {}
        .offset(x = offset.dp)
        .background(Color.Red)
        .size(100.dp)
)

Slider(value = offset, onValueChange = { offset = it }, valueRange = 0f..200f)

修饰符指针输入(键)

该修饰符是手势和触摸事件的基础。使用它可以调用拖动、点击、按下、双击、缩放、旋转和许多手势。在此answer中解释了如何使用它来构建View系统的onTouchEvent对应物。
与上面的修改器不同,它默认从下向上传播,除非你消耗PointerInputChange。在合成手势系统中,消耗连续事件取消下一个事件以接收它。因此,你可以防止像滚动这样的手势在你缩放图像时不发生。

Modifier
   .pointerInput() // Second one that is invoked
   .pointerInput() // First one that is invoked

相关问题