Составить реактивный ранец - Порядок модификаторов

В документации сказано, что модификаторы применяются слева. Но из этого примера похоже, что они применяются справа: сначала граница, а затем отступ, потому что между текстом и рамкой нет пробела.

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

введите описание изображения здесь


person ivoronline    schedule 05.10.2020    source источник


Ответы (4)


В программе Jetpack Compose есть макеты, содержащие Модификаторы макета под капотом, объясняющий порядок модификаторов, см. раздел Порядок действий.

порядок имеет значение при связывании модификаторов, поскольку они применяются к составному объекту, который они изменяют от более раннего к более позднему, что означает, что измерение и расположение модификаторов слева повлияют на модификатор справа. Окончательный размер составного объекта зависит от всех модификаторов, переданных в качестве параметра. Сначала модификаторы обновят ограничения слева направо, а затем вернут размер справа налево.

Чтобы лучше понять это, я бы рекомендовал выяснить, как макеты работают в 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 в аргументы, составной объект позволяет его родителям добавлять дополнительные модификаторы, такие как дополнительное поле. Поскольку модификаторы, добавленные последними, находятся ближе всего к кнопке, граница и внутреннее заполнение не пострадают.

person Valeriy Katkov    schedule 13.01.2021

  • В Android Compose результирующее изображение создается от внешнего слоя к Composable в центре. Это означает, что первая определенная зеленая граница является внешней границей, а последняя определенная красная граница - внутренней. Это очень сбивает с толку, поскольку зеленый модификатор, который ближе всего к Text Composable в коде, находится дальше всего от него в результате.
  • Это отличается от SwiftUI, где модификаторы появляются в том же порядке как в коде, так и в результирующем изображении. Модификатор, который ближе всего к Composable в коде, также наиболее близок к нему в результирующем изображении.
  • Если вы хотите представить, что результирующее изображение создается из центра, в котором расположен ваш составной объект (как в SwiftUI), то модификаторы применяются в порядке, обратном их порядку (снизу вверх).
  • So if you have Text Composable with two border Modifiers
    • border Modifier that is furthest away from the Text Composable in the Code (the bottom Red one)
    • будет ближе всего к Text Composable в итоговом изображении
  • Modifiers are applied from outer toward inner layer
    • Applying .border(2.dp, Color.Green) to the outmost layer
    • Применение .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)
      )
    }
  }
}

введите описание изображения здесь

person ivoronline    schedule 06.10.2020

Первый отступ в этом случае похож на поле для элемента.

Сравните эти составные части, и вы увидите разницу.

@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))
    }
}

Визуализация данного примера

person 2jan222    schedule 05.10.2020

Элементы-модификаторы можно комбинировать с помощью then. Порядок важен; элементы модификатора, которые появляются первыми, будут применены первыми. @ здесь

Сначала он применяется к внешнему слою с отступом 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)
    )
}

введите описание изображения здесь

person Eric Cen    schedule 05.10.2020
comment
Вы говорите, что сначала это относится к внешнему слою. Разве это не обратное мышление? Не было бы логичнее начать с самого текста (внутреннего слоя) и посмотреть, как он изменяется с помощью различных модификаторов вовне? Итак, ваш образ мышления состоит в том, что вы идете вовне и внутрь, применяя модификаторы, как они определены. Вы можете получить тот же результат, двигаясь изнутри наружу, применяя модификаторы в обратном порядке (как я сказал в своем сообщении). Другими словами, для меня логичнее начать с текста (внутренний слой), но в этом случае мне нужно применить модификаторы в обратном порядке, чтобы предсказать результат. - person ivoronline; 06.10.2020
comment
.padding (10.dp) ближе всего к тексту в коде, но дальше всего на изображении. Это нелогично. .padding (80.dp) дальше всего от текста в коде, но ближе всего к тексту на изображении. Это нелогично. Но из этого я прихожу к выводу, что на самом деле модификаторы применяются в обратном порядке: в первую очередь применяются те, которые находятся дальше в коде. - person ivoronline; 06.10.2020
comment
Если вы используете свой подход, он сначала применяется к внешнему слою, это означает, что когда вы сначала читаете Код, вы видите текст, затем вы перескакиваете куда-нибудь подальше от текста (внешний слой) и возвращаетесь к тексту, применяя модификаторы от внешнего к внутреннему слою. Для меня это не имеет смысла. Для меня более логично, что мы строим изображение так же, как читаем код. Сначала есть текст. Затем рядом с ним находится первый модификатор в коде, и он также должен быть на изображении. И поэтому мы строим изображение в том же порядке, в котором читаем код. Изнутри наружу, потому что код начинается с текста, который находится внутри - person ivoronline; 06.10.2020
comment
Поэтому, когда я говорю, что модификаторы применяются в противоположном направлении, я имею в виду, что модификаторы, которые ближе всего к тексту в коде, находятся дальше в результирующем изображении. Изображение идет в противоположном направлении от кода - следовательно, модификаторы применяются в противоположном направлении. . В коде пурпурная граница определяется ПЕРЕД красной рамкой и БЛИЖЕ к тексту. Но в результирующем изображении все наоборот: красная граница БЛИЖЕ к тексту, хотя она определена после пурпурной границы. - person ivoronline; 06.10.2020
comment
Эквивалентный код в SwiftUI дает противоположный результат. Там пурпурная граница будет ближе к тексту как в коде, так и в изображении. Потому что там каждый модификатор возвращает новый измененный вид. Итак, модификаторы действительно используются в том направлении, в котором они определены. Вы начинаете с текстового представления. Вы применяете модификатор Magenta, который возвращает новый вид с пурпурной рамкой вокруг текста. Затем к этому представлению вы применяете отступы и красную границу, чтобы красная граница стала внешней. Все логично и течет в одном и том же естественном направлении как в коде, так и в результирующем изображении. - person ivoronline; 06.10.2020