Jetpack Compose - 修饰符顺序

ivo*_*ine 8 android modifier android-jetpack android-jetpack-compose

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

Text("Hi there!", Modifier.padding(10.dp).border(2.dp, Color.Magenta))
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

Val*_*kov 21

Jetpack Compose 代码实验室中有Layouts,其中包含解释修饰符顺序的Layout 修饰符,请参阅“顺序很重要”部分。

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

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

让我们看一个例子:

Box(
  modifier = Modifier
    .border(1.dp, Color.Red)
    .size(32.dp)
    .padding(8.dp)
    .border(1.dp, Color.Blue)
)
Run Code Online (Sandbox Code Playgroud)

结果:

在此处输入图片说明

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

Box(
  modifier = Modifier
    .border(1.dp, Color.Red)
    .padding(8.dp)
    .size(32.dp)
    .border(1.dp, Color.Blue)
)
Run Code Online (Sandbox Code Playgroud)

现在我们有不同的结果:

在此处输入图片说明

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

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

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

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

  • 哇,不仅顺序很重要,而且可以多次调用“border()”来创建多个边框,这很有趣 (6认同)

ivo*_*ine 16

  • 在 Android Compose 中,生成的 Image 是从外层向中心的 Composable 构建的。这意味着第一个定义的绿色边框是外边框,最后定义的红色边框是内边框。这是非常令人困惑的,因为代码中最接近文本可组合的绿色修饰符在结果中距离它最远。
  • 这与 SwiftUI 形成鲜明对比,在 SwiftUI 中,修饰符在代码和生成的图像中都以相同的顺序出现。代码中最接近可组合项的修饰符在生成的图像中也最接近它。
  • 如果您想想象生成的 Image 是从您的 Composable 所在的中心构建的(就像在 SwiftUI 中一样),那么修饰符会按照与给出的顺序相反的顺序应用(从下到上)。
  • 因此,如果您有带有两个边框修饰符的 Text Composable
    • 距离代码中可组合文本最远的边框修饰符(底部的红色)
    • 将最接近生成图像中的可组合文本
  • 改性剂从外层向内层应用
    • 将 .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)
      )
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Thr*_*ian 6

Modifier 允许我们自定义可组合项的外观。使用它,您可以:

\n
    \n
  • 更改可组合\xe2\x80\x99s 的外观、大小、偏移、填充或边距
  • \n
  • 添加交互,例如使元素可点击、可滚动、可拖动或可缩放
  • \n
  • 更改其比例、在屏幕中的位置,同时其布局完全不同,或者改变其触摸区域的形状。
  • \n
\n

根据您放置这些修饰符的顺序,您的可组合项的视觉和行为结构将被塑造。

\n

大多数修饰符都是从上到下或从左到右应用的。一个例外是 Modifier.pointerInput(),它默认从右到左或从下到上应用。

\n

修饰符.padding()

\n

Modifier.padding()在 Jetpack Compose 中,根据顺序充当填充或边距。

\n

Modifier.padding(10.dp).size(200.dp)在设置大小之前添加空间,您有一个大小为200.dp的可组合项

\n

Modifier.size(200.dp).padding(10.dp)在每侧设置 10.dp 填充后,添加宽度和高度为180.dp 的填充。

\n
Box(\n    Modifier\n        .border(2.dp, Color.Green)\n        .padding(10.dp)\n        .border(2.dp, Color.Red)\n        .size(200.dp)\n)\n\nBox(\n    Modifier\n        .border(2.dp, Color.Cyan)\n        .size(200.dp)\n        .padding(10.dp)\n        .border(2.dp, Color.Magenta)\n)\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n

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

\n

在此输入图像描述

\n
Box(\n    Modifier\n        .border(2.dp, Color.Green)\n        .padding(20.dp)\n        .border(2.dp, Color.Red)\n        .size(200.dp)\n)\n\nBox(\n    Modifier\n        .border(2.dp, Color.Green)\n        .padding(20.dp)\n        .padding(20.dp)\n        .border(2.dp, Color.Red)\n        .size(200.dp)\n)\n
Run Code Online (Sandbox Code Playgroud)\n

修饰符.shadow()

\n

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

\n
Box(\n    Modifier\n        .shadow(5.dp, RoundedCornerShape(8.dp))\n        .background(Color.White)\n        .size(100.dp)\n)\n\nBox(\n    Modifier\n        .background(Color.White)\n        .size(100.dp)\n        .shadow(5.dp, RoundedCornerShape(8.dp))\n) \n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n

修改器.clip()

\n

此修改器还会根据其放置顺序来剪辑修改器。Modifier.clickable{}如果您将其放置在可以更改或剪辑可组合项的可点击区域之前,那么此修改器是有好处的。使用此修改器和 s 可以拥有圆形、三角形或菱形圆形区域或创建之前/之后布局Shape

\n

它在Modifier.graphicsLayer{}幕后,你可以在这里这里这里查看我关于它的详细答案。它可以帮助您使用缩放、形状、剪辑、翻译和其他很酷的属性创建复杂的布局。

\n

在此输入图像描述

\n

修饰符.offset()

\n

与 Modifier 不同,此修饰符可用于在布局后更改可组合项的位置。填充更改此修饰符的值不会更改可组合项相对于其同级可组合项的位置。但是,根据您设置 Modifier.offset 的位置,您可以更改可组合项的触摸区域,并且它有两个变体。采用 lambda延迟状态读取的一种方式是谷歌建议的,而不是采用值的方式。

\n

我用了一个有演示价值的。您可以看到是否首先应用偏移量修改器,随着滑块更改值,偏移量会移动。在第二个示例中,可组合项的触摸区域没有更改,因为Modifier.clickable{}之前已应用Modifier.offset{}

\n
var offset by remember {\n    mutableStateOf(0f)\n}\nBox(\n    Modifier\n        .offset(x = offset.dp)\n        .clickable {}\n        .background(Color.Red)\n        .size(100.dp)\n)\n\nBox(\n    Modifier\n        .clickable {}\n        .offset(x = offset.dp)\n        .background(Color.Red)\n        .size(100.dp)\n)\n\nSlider(value = offset, onValueChange = { offset = it }, valueRange = 0f..200f)\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n

Modifier.pointerInput(键)

\n

该修饰符是手势和触摸事件的基础。使用它可以调用拖动、点击、按下、双击、缩放、旋转和许多手势。在这个答案中解释了如何使用它来构建视图系统的 onTouchEvent 对应部分。

\n

与上面的修饰符不同,它默认从下到上传播,除非您使用 PointerInputChange。在 Compose 手势系统中,消耗连续事件会取消队列中的下一个事件来接收它。因此,您可以防止在缩放图像时发生诸如滚动之类的手势。

\n
Modifier\n   .pointerInput() // Second one that is invoked\n   .pointerInput() // First one that is invoked\n
Run Code Online (Sandbox Code Playgroud)\n