Compose'da ConstraintLayout

ConstraintLayout, bileşenleri ekrandaki diğer bileşenlere göre yerleştirmenize olanak tanıyan bir düzendir. Birden çok iç içe yerleştirilmiş Row, Column, Box ve diğer özel düzen öğelerini kullanmaya alternatiftir. ConstraintLayout daha karmaşık hizalama koşullarına sahip daha büyük düzenler uygularken kullanışlıdır.

Aşağıdaki senaryolarda ConstraintLayout kullanabilirsiniz:

  • Kodun okunabilirliğini artırmak için öğeleri ekranda konumlandırmak üzere birden fazla Column ve Row iç içe yerleştirmekten kaçının.
  • Bileşenleri diğer bileşenlere göre konumlandırmak veya bileşenleri kurallara, bariyerlere ya da zincirlere göre konumlandırmak için kullanılır.

Görüntüleme sisteminde, düz görünüm hiyerarşisi performans açısından iç içe yerleştirilmiş görünümlerden daha iyi olduğu için büyük ve karmaşık düzenler oluşturmak için önerilen yöntem ConstraintLayout idi. Ancak bu, derin düzen hiyerarşilerini verimli bir şekilde yönetebilen Compose'da sorun yaratmaz.

ConstraintLayout hizmetini kullanmaya başla

Oluşturma'da ConstraintLayout'ü kullanmak için build.gradle'unuza bu bağımlılığı eklemeniz gerekir (Oluşturma kurulumuna ek olarak):

implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"

Oluştur'daki ConstraintLayout, DSL kullanarak aşağıdaki şekilde çalışır:

  • createRefs() veya createRefFor() kullanarak ConstraintLayout içindeki her composable için referans oluşturun
  • Kısıtlamalar, referansı parametre olarak alan ve gövde lambda'sında kısıtlamalarını belirtebilmenizi sağlayan constrainAs() değiştiricisi kullanılarak sağlanır.
  • Kısıtlamalar linkTo() veya diğer faydalı yöntemler kullanılarak belirtilir.
  • parent, ConstraintLayout composable'ına yönelik kısıtlamaları belirtmek için kullanılabilecek mevcut bir referanstır.

ConstraintLayout kullanan bir bileşen örneğini aşağıda bulabilirsiniz:

@Composable
fun ConstraintLayoutContent() {
    ConstraintLayout {
        // Create references for the composables to constrain
        val (button, text) = createRefs()

        Button(
            onClick = { /* Do something */ },
            // Assign reference "button" to the Button composable
            // and constrain it to the top of the ConstraintLayout
            modifier = Modifier.constrainAs(button) {
                top.linkTo(parent.top, margin = 16.dp)
            }
        ) {
            Text("Button")
        }

        // Assign reference "text" to the Text composable
        // and constrain it to the bottom of the Button composable
        Text(
            "Text",
            Modifier.constrainAs(text) {
                top.linkTo(button.bottom, margin = 16.dp)
            }
        )
    }
}

Bu kod, Button öğesinin üst kısmını 16.dp kenar boşluğuyla ebeveyne, Button öğesinin alt kısmını da 16.dp kenar boşluğuyla Text öğesine sınırlar.

ConstraintLayout içinde düzenlenmiş bir düğme ve metin öğesi gösterir

Ayrıştırılmış API

ConstraintLayout örneğinde, kısıtlamalar uygulandıkları composable'daki bir değiştiriciyle satır içinde belirtilmektedir. Bununla birlikte, bazı durumlarda kısıtlamaların geçerli oldukları düzenlerden ayrılması tercih edilir. Örneğin, kısıtlamaları ekran yapılandırmasına göre değiştirmek veya iki kısıtlama grubu arasında animasyon yapmak isteyebilirsiniz.

Bu gibi durumlarda ConstraintLayout öğesini farklı bir şekilde kullanabilirsiniz:

  1. ConstraintLayout işlevine parametre olarak bir ConstraintSet gönderin.
  2. layoutId değiştiricisini kullanarak ConstraintSet özelliğinde oluşturulan referansları composable'lara atayın.

@Composable
fun DecoupledConstraintLayout() {
    BoxWithConstraints {
        val constraints = if (minWidth < 600.dp) {
            decoupledConstraints(margin = 16.dp) // Portrait constraints
        } else {
            decoupledConstraints(margin = 32.dp) // Landscape constraints
        }

        ConstraintLayout(constraints) {
            Button(
                onClick = { /* Do something */ },
                modifier = Modifier.layoutId("button")
            ) {
                Text("Button")
            }

            Text("Text", Modifier.layoutId("text"))
        }
    }
}

private fun decoupledConstraints(margin: Dp): ConstraintSet {
    return ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        constrain(button) {
            top.linkTo(parent.top, margin = margin)
        }
        constrain(text) {
            top.linkTo(button.bottom, margin)
        }
    }
}

Daha sonra, kısıtlamaları değiştirmeniz gerektiğinde farklı bir ConstraintSet iletebilirsiniz.

ConstraintLayout kavram

ConstraintLayout, Composable'ınızdaki öğeleri yerleştirmenize yardımcı olabilecek kurallar, engeller ve zincirler gibi kavramlar içerir.

Kurallar

Kurallar, düzenler tasarlamak için kullanabileceğiniz küçük görsel yardımcılardır. Birleştirilebilirler bir yönergeyle sınırlanabilir. Kılavuzlar, öğeleri üst bileşimin içinde belirli bir dp veya percentage konumuna yerleştirmek için kullanışlıdır.

Dikey ve yatay olmak üzere iki farklı yönerge türü vardır. İki yatay olan top ve bottom, dikey ise start ve end şeklindedir.

ConstraintLayout {
    // Create guideline from the start of the parent at 10% the width of the Composable
    val startGuideline = createGuidelineFromStart(0.1f)
    // Create guideline from the end of the parent at 10% the width of the Composable
    val endGuideline = createGuidelineFromEnd(0.1f)
    //  Create guideline from 16 dp from the top of the parent
    val topGuideline = createGuidelineFromTop(16.dp)
    //  Create guideline from 16 dp from the bottom of the parent
    val bottomGuideline = createGuidelineFromBottom(16.dp)
}

Kural oluşturmak için gerekli kural türüyle birlikte createGuidelineFrom* kullanın. Bu, Modifier.constrainAs() bloğunda kullanılabilecek bir referans oluşturur.

Bariyerler

Engeller, belirtilen taraftaki en uç widget'a dayalı sanal bir kılavuz oluşturmak için birden fazla bileşene referans verir.

Bariyer oluşturmak için createTopBarrier() (veya: createBottomBarrier(), createEndBarrier(), createStartBarrier()) kullanın ve bariyerin oluşturulmasını istediğiniz referansları sağlayın.

ConstraintLayout {
    val constraintSet = ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        val topBarrier = createTopBarrier(button, text)
    }
}

Engel daha sonra bir Modifier.constrainAs() bloğunda kullanılabilir.

Zincirler

Zincirler, tek bir eksende (yatay veya dikey) grup benzeri bir davranış sağlar. Diğer eksen bağımsız olarak kısıtlanabilir.

Zincir oluşturmak için createVerticalChain veya createHorizontalChain simgesini kullanın:

ConstraintLayout {
    val constraintSet = ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        val verticalChain = createVerticalChain(button, text, chainStyle = ChainStyle.Spread)
        val horizontalChain = createHorizontalChain(button, text)
    }
}

Zincir daha sonra Modifier.constrainAs() bloğunda kullanılabilir.

Bir zincir, farklı ChainStyles ile yapılandırılabilir. Bu ChainStyles, bir bileşeni çevreleyen alanla nasıl başa çıkılacağına karar verir. Örneğin:

  • ChainStyle.Spread: Alan, ilk bileşenden önceki ve son bileşenden sonraki boş alan da dahil olmak üzere tüm bileşenlere eşit olarak dağıtılır.
  • ChainStyle.SpreadInside: Boşluk, ilk bileşenden önce veya son bileşenden sonra boşluk bırakılmadan tüm bileşenler arasında eşit olarak dağıtılır.
  • ChainStyle.Packed: Boşluk, ilk derlenebilir öğenin önüne ve son derlenebilir öğenin arkasına dağıtılır. Derlenebilir öğeler, aralarında boşluk olmadan birlikte paketlenir.

Daha fazla bilgi

ConstraintLayout kullanan Compose örnekleri bölümünde, API'lerin kullanıldığı Compose'daki ConstraintLayout hakkında daha fazla bilgi edinin.