Установка ограничений в ConstraintLayout

Последнее обновление: 07.04.2024

Хотя мы можем так делать, как в примере выше, но в этом смысла нет, поскольку в этом случае проще воспользоваться стандартными типами контейнеров типа Box. Ключевой момент ConstraintLayout заключается именно в установке ограничений для вложенных компонентов. Наиболее распространенная форма ограничения — это ограничения относительно родительского контейнера ConstraintLayout или другого компонента.

Для установки для компонента ограничений этому компоненту необходимо назначить ссылку. Назначение ссылки представляет двухэтапный процесс, который состоит из создания ссылки и последующего ее назначения компонентам перед применением ограничений. Ccылка представляет объект класса ConstrainedLayoutReference, и одну ссылку можно создать с помощью вызова функции createRef() и затем присвоить результат константе:

val box1 = createRef()

Для создания нескольких ссылок можно использовать функцию createRefs():

val (box1, text1, text2) = createRefs()

После создания ссылок они применяются к отдельным компонентам с помощью функции-модификатора constrainAs():

Modifier.constrainAs(
    ref: ConstrainedLayoutReference,
    constrainBlock: ConstrainScope.() -> Unit
)

Этот модификатор принимает два параметра:

  • Первый параметр - это созданная ссылка в виде объекта ConstrainedLayoutReference

  • Второй параметр представляет функцию, которая устанавливает ограничения.

Например, следующий код присваивает ссылку box1 компоненту Box:

ConstraintLayout {
    val box1 = createRef()
    Box(modifier = Modifier.constrainAs(box1) {
        // здесь идут ограничения
    })
}

Здесь в компоненте Box модификатору constrainAs() передается ссылка "box1". Таким образом, далее мы сможем ссылаться на этот компонент Box через ссылку box1.

ConstrainScope

Второй параметр модификатора constrainAs() представляет функцию, в которой и устанавливаются ограничения. Для этого внутри данной функции можно использовать свойства класса ConstrainScope/ConstrainedLayoutReference:

  • absoluteLeft: левый край компонента

  • absoluteRight: правый край компонента

  • baseline: базовая линия компонента

  • bottom: нижний край компонента

  • top: верхний край компонента

  • start: начало компонента (правый или левый крайв зависимости от направления текста)

  • end: конец компонента (правый или левый крайв зависимости от направления текста)

Кроме того, ConstrainScope предоставляет специальное свойство parent, который представляет ссылку на родительский контейнер в виде объекта ConstrainedLayoutReference и через который можно обратиться к этим же свойствам родительского контейнера.

Одним из способов установить ограничения представляет вызов функции linkTo(). Она вызывается у выше рассмотренных свойств. Например:

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.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.compose.ui.tooling.preview.Preview

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent{
            ConstraintLayout {
                val rect = createRef()
                Box(Modifier.size(200.dp).background(Color.DarkGray).constrainAs(rect) {
                    top.linkTo(parent.top, margin = 16.dp)
                })
            }
        }
    }
}

В данном случае строка

top.linkTo(parent.top, margin = 16.dp)

представляет установку ограничения для верхнего края компонента Box (свойство top). Соответственно выражение top.linkTo() говорит установить ограничение для верхнего края компонента Box.

Настройки ограничения передаются в вызов функции. Первый аргумент - относительно какой стороны надо установить ограничение, а второй аргумент - отступ. В данном случае первый аргумент - parent.top указывает на верхний край родительского контейнера, а второй аргумент - margin = 16.dp задает отступ в 16 пикселей. Таким образом, этот код ограничивает верхний край компонента Box верхним краем родительского экземпляра ConstraintLayout с отступом в 16 пикселей:

ConstraintLayout и функция linkTo в Jetpack Compose на Kotlin на Android

Подобным образом можно установить и другие ограничения:

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.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent{
            ConstraintLayout(Modifier.fillMaxSize()) {
                val box1 = createRef()
                Box(Modifier.size(200.dp).background(Color.DarkGray).constrainAs(box1) {
                    absoluteLeft.linkTo(parent.absoluteLeft, margin = 16.dp) // отступ слева
                    top.linkTo(parent.top, margin = 16.dp)      // отступ сверху
                })
            }
        }
    }
}

Для установки ограничений ConstrainScope также предоставляет другую форму функции linkTo(), которая может передавать несколько ограничений в качестве параметров. Однак из ее форм:

fun linkTo(
    start: ConstraintLayoutBaseScope.VerticalAnchor,
    top: ConstraintLayoutBaseScope.HorizontalAnchor,
    end: ConstraintLayoutBaseScope.VerticalAnchor,
    bottom: ConstraintLayoutBaseScope.HorizontalAnchor,
    startMargin: Dp = 0.dp,
    topMargin: Dp = 0.dp,
    endMargin: Dp = 0.dp,
    bottomMargin: Dp = 0.dp,
    startGoneMargin: Dp = 0.dp,
    topGoneMargin: Dp = 0.dp,
    endGoneMargin: Dp = 0.dp,
    bottomGoneMargin: Dp = 0.dp,
    horizontalBias: @FloatRange(from = 0.0, to = 1.0) Float = 0.5f,
    verticalBias: @FloatRange(from = 0.0, to = 1.0) Float = 0.5f
): Unit

Первый 4 параметра устанавливаются ограничения для соответственно сторон start, top, end, bottom текущего компонента, а следующие 4 параметра настраивают отступы.

Пример применения:

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.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent{
            ConstraintLayout(Modifier.fillMaxSize()) {
                val box1 = createRef()
                Box(Modifier.size(200.dp).background(Color.DarkGray).constrainAs(box1) {
                    linkTo(start=parent.start,top=parent.top, end = parent.end, bottom=parent.bottom, 16.dp, 16.dp, 16.dp, 16.dp)
                })
            }
        }
    }
}
ConstraintLayout и установка ограничений с помощью функции linkTo в Jetpack Compose на Kotlin на Android

Ограничения относительно другого компонента

Аналогичным образом можно устанавливать ограничения относительно других компонентов:

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.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent{
            ConstraintLayout(Modifier.fillMaxSize()) {
                val box1 = createRef()
                val box2 = createRef()
                Box(Modifier.size(150.dp).background(Color.DarkGray).constrainAs(box1) {
                    absoluteLeft.linkTo(parent.absoluteLeft, margin = 16.dp) // отступ слева
                    top.linkTo(parent.top, margin = 16.dp) // отступ сверху
                })

                Box(Modifier.size(150.dp).background(Color.Red).constrainAs(box2) {
                    absoluteLeft.linkTo(box1.absoluteRight, margin = 16.dp) // отступ слева от box1
                    top.linkTo(parent.top, margin = 16.dp) // отступ сверху
                })
            }
        }
    }
}

Здесь создается две ссылки - box1 и box2 для двух компонентов Box. Компонент box1 устанавливает ограничения относительно верхней и левой стороны контейнера. А компонент box2 устанавливает ограничение левой стороны относительно правой стороны компонента box1 с отступом в 16 пикселей.

ConstraintLayout и ограничения относительно других компонентов в Jetpack Compose на Kotlin на Android

Центрирование компонентов

Кроме функции linkTo() для установки ограничений можно применять ряд функций, который центрируют компонент относительно родительского контейнера или других компонентов:

  • centerHorizontallyTo(): располагает по центру по горизонтали

  • centerVerticallyTo(): располагает по центру по вертикали

  • centerAround(): центрирует по определенной стороне контейнера или другого компонента

  • centerTo(): центрирует одновременно и по горизонтали и по вертикали

Например,

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.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent{
            ConstraintLayout(Modifier.fillMaxSize()) {
                val box1 = createRef()
                val box2 = createRef()
                Box(Modifier.size(150.dp).background(Color.DarkGray).constrainAs(box1) {
                    absoluteLeft.linkTo(parent.absoluteLeft, margin = 16.dp) // отступ слева
                    top.linkTo(parent.top, margin = 16.dp) // отступ сверху
                })

                Box(Modifier.size(100.dp).background(Color.Red).constrainAs(box2) {
                    centerVerticallyTo(box1)
                    centerHorizontallyTo(parent)
                })
            }
        }
    }
}

В данном случае box2 центрируется по горизонтали относительно родительского контейнера, а по вертикали располагается по центру box1:

ConstraintLayout и центрирование компонентов в Jetpack Compose на Kotlin на Android

Центрирование с помощью centerAround()

ConstraintLayout(Modifier.fillMaxSize()) {
    val box1 = createRef()
    val box2 = createRef()
    Box(Modifier.size(150.dp).background(Color.DarkGray).constrainAs(box1) {
        absoluteLeft.linkTo(parent.absoluteLeft, margin = 16.dp)
        top.linkTo(parent.top, margin = 16.dp)
    })

    Box(Modifier.size(100.dp).background(Color.Red).constrainAs(box2) {
        centerAround(box1.absoluteRight)
        centerAround(box1.bottom)
    })
}

Взаимная установка ограничений

Различные компоненты могут взаимно устанавливать ограничения относительно друг друга. Например:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent{
            ConstraintLayout(Modifier.fillMaxSize()) {
                val (text1, text2) = createRefs()

                Text("TV", fontSize = 54.sp, modifier = Modifier.constrainAs(text1) {
                    centerHorizontallyTo(parent)
                    top.linkTo(parent.top)
                    bottom.linkTo(text2.top)
                })

                Text("Radio", fontSize = 54.sp, modifier = Modifier.constrainAs(text2) {
                    centerHorizontallyTo(parent)
                    top.linkTo(text1.bottom)
                    bottom.linkTo(parent.bottom)
                })
            }
        }
    }
}

Здесь оба компонента Text располагаются по центру контейнера по горизонтали. Но при этом верхняя граница text2 проходит по нижней границе text1, тогда как нижняя граница text1 - по верхней границе text2.

ConstraintLayout и взаимная установка ограничения компонентов в Jetpack Compose на Kotlin на Android

Смещение

Применение смещения позволяет перемещать компонент относительно доступного пространства:

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.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent{
            ConstraintLayout(Modifier.fillMaxSize()) {
                val (box1, box2) = createRefs()
                Box(Modifier.size(150.dp).background(Color.DarkGray).constrainAs(box1) {

                    top.linkTo(parent.top, margin = 60.dp)
                    linkTo(parent.start, parent.end)
                })

                Box(Modifier.size(150.dp).background(Color.Red).constrainAs(box2) {
                    top.linkTo(parent.top, margin = 60.dp)
                    linkTo(parent.start, parent.end, bias = 0.75f)
                })
            }
        }
    }
}

Здесь оба компонента Box по умолчанию позиционируются в одно и то же место, однако box2 при этом сдвинут на 75% доступной ширины:

ConstraintLayout и bias в Jetpack Compose на Kotlin на Android
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850