В Jetpack Compose за расположение и компоновку компонентов в приложении отвечает специальный компонент - Layout. Он имеет следующую сигнатуру:
@Composable inline fun Layout( content: @Composable () -> Unit, modifier: Modifier = Modifier, measurePolicy: MeasurePolicy )
Он имеет следующие параметры:
content
: Composable-функция, которая хранит все вложенные компоненты
modifier
: объект Modifier, которые устанавливает функции-модификаторы, применяемые для стилизации компонента
measurePolicy
: объект, который отвечает за вычисление размеров компонентов и их определение их расположения
Создание своего алгоритма вычисления размеров компонентов внутри компонента-контейнера, должная компоновка вложенных компонентов представляют трудоемкую работу, поэтому фреймворк Compose предоставляет ряд встроенных компонентов-контейнеров, которые автоматически выполняют эту работу. Основными из них являются Box, Row и Column. Рассмотрим эти контейнеры.
Компонент Box является наиболее простым контейнером, позволяя позиционировать вложенное содержимое. Он представляет некоторую область экрана. Функция данного компонента принимает четыре параметра:
@Composable inline fun Box( modifier: Modifier = Modifier, contentAlignment: Alignment = Alignment.TopStart, propagateMinConstraints: Boolean = false, content: @Composable BoxScope.() -> Unit ): @Composable Unit
modifier: объект Modifier, который позволяет настроить внешний вид и поведение компонента с помощью модификаторов
contentAlignment: объект Alignment, который устанавливает расположение компонента. По умолчанию
имеет значение Alignment.TopStart
(расположение вначале контейнера в верхнем углу)
propagateMinConstraints: значение типа Boolean, который
указывает, надо ли применять к содержимому ограничения по минимальным размерам. По умолчанию равно false
(ограничения не применяются)
content: объект интерфейса BoxScope, который представляет вложенное содержимое
Контейнер Box может использоваться как самодостаточный компонент без какого-либо вложенного содержимого:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.size import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Box( modifier = Modifier.size(300.dp, 250.dp).background(Color.Blue) ) } } }
Для установки визуальных свойств объекта Box применяется свойство modifier, которое представляет объект Modifier, рассмотренный в прошлой главе. Как и для других компонентов, для компонента Box мы можем вызвать функцию size(), которая принимает ширину и длину контейнера - в данном случае ширина 300 единиц и высота 250 единиц.
Modifier.size(300.dp, 250.dp)
Эта функция опять же возвращает объект Modifier, у которого далее вызыватся другая функция -
background(), которая устанавливает фоновый цвет контейнера - в данном случае синий цвет или значение Color.Blue
Modifier.size(300.dp, 250.dp).background(Color.Blue)
В итоге мы увидим на экране синюю прямоугольную область размером 300 x 250.
По умолчанию Box занимает те размеры на экране, которые необходимы, чтобы вместить содержимое. Но выше в Box никакого вложенного содержимого не было,
поэтому чтобы установить размеры, применялся объект Modifier
и его функция size()
Modifier.size(300.dp, 250.dp)
Если необходимо растянуть элемент по всей ширине и длине экрана, то, как и в общем случае, применяется функция - fillMaxSize():
Modifier.fillMaxSize().background(Color.Blue)
Например, определим простейший элемент Box с вложенным элементом Text
:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Box import androidx.compose.material3.Text import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Box { Text("Hello METANIT.COM", fontSize = 28.sp,) } } } }
Здесь мы видим, что вложенный компонент Text позиционируется в левом верхнем углу контейнера Box.
Есть три причины подобного позиционирования
Элемент Box сам по умолчанию располагается в верхнем левом углу устройства
Для Box не задано размеров, он будет стремиться занять пространство, необходимое для вложенного содержимого.
Если вложенное содержимое меньше размеров контейнера Box, то для его позиционирования внутри Box будет использоваться настройка contentAlignment.
А по умолчанию применяет значение Alignment.TopStart
(расположение вначале контейнера в верхнем углу)
Для позиционирования внутри Box данный компонент определяет параметр contentAlignment, которому передаются свойства объекта Alignment:
Alignment.BottomCenter
: внизу по центру
Alignment.BottomEnd
: внизу в конце
Alignment.BottomStart
: внизу в начале
Alignment.Center
: по центру по вертикали и горизонтали
Alignment.CenterEnd
: по центру про вертикали и в конце по горизонтали
Alignment.CenterStart
: по центру про вертикали и в начале по горизонтали
Alignment.TopCenter
: вверху по центру
Alignment.TopEnd
: вверху в конце
Alignment.TopStart
: вверху в начале
Здесь для определения расположения применяются такие слова как "начало" (Start) и "конец" (End). В зависимости от яхыка системы и системы письма - правосторонняя или левосторонняя начало и конец как может находиться справа, так и слева. Например, для подавляющего числа языков (в том числе русского) начало находится слева, а конец - справа.
Например, расположим вложенные элементы по центру:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Text import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Box( contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize() ){ Text("Hello METANIT.COM", fontSize = 28.sp,) } } } }
Значение Alignment.Center
указывает, что содержимое будет позиционироваться по центру как по горизонтали, так и по вертикали. А чтобы Box был растянут по всей площади экрана, применяется модификатор
Modifier.fillMaxSize()
:
Если Box содержит несколько вложенных компонентов, то умолчанию они будут накладываться друг на друга в порядке следования (последний компонент располагается поверх предыдущих)
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Text import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { Box(modifier = Modifier.background(Color.DarkGray).size(320.dp)) Box(modifier = Modifier.background(Color.LightGray).size(280.dp)) Text("Hello METANIT.COM", fontSize = 28.sp, modifier =Modifier.padding(10.dp)) } } } }
В Box мы можем задать расположение не только для всех вложенных компонентов в целом, но и для каждого компонента по отдельности. При определении компонентов внутри Box
на компонентах можно определить модификатор align, который принимает вышерассмотренный объект
Alignment и позволяет настроить положение каждого отдельного компонентов внутри Box:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Text import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { Text("TopStart", fontSize = 28.sp, modifier =Modifier.align(Alignment.TopStart)) Text("TopEnd", fontSize = 28.sp, modifier =Modifier.align(Alignment.TopEnd)) Text("Center", fontSize = 28.sp, modifier =Modifier.align(Alignment.Center)) Text("BottomStart", fontSize = 28.sp, modifier =Modifier.align(Alignment.BottomStart)) Text("BottomEnd", fontSize = 28.sp, modifier =Modifier.align(Alignment.BottomEnd)) } } } }