Compose'da ConstraintLayout

ConstraintLayout, ekrandaki diğer composable'lara göre composable'lar yerleştirmenize olanak tanıyan bir düzendir. İç içe yerleştirilmiş birden fazla Row, Column, Box ve diğer özel düzen öğesini kullanmaya alternatiftir. ConstraintLayout, daha karmaşık hizalama gereksinimleriyle daha büyük düzenler uygularken kullanışlıdır.

Aşağıdaki senaryolarda ConstraintLayout kullanabilirsiniz:

  • Kodun okunabilirliğini iyileştirmek amacıyla ekrandaki öğeleri konumlandırmak için birden fazla Column ve Row öğesinin iç içe yerleştirilmemesini sağlamak amacıyla.
  • composable'ları diğer composable'lara göre konumlandırmak ya da composable'ları yönergelere, bariyerlere veya zincirlere göre konumlandırmak.

Düz görünüm hiyerarşisi, iç içe yerleştirilmiş görünümlere kıyasla daha iyi performans gösterdiğinden, Görünüm sisteminde büyük ve karmaşık düzenler oluşturmak için ConstraintLayout kullanılması önerilir. Ancak bu, derin düzen hiyerarşilerini verimli bir şekilde yönetebilen Compose'da sorun yaratmaz.

ConstraintLayout hizmetini kullanmaya başla

ConstraintLayout öğesini Compose'da kullanmak için bu bağımlılığı build.gradle sayfanıza (Compose ayarlarına ek olarak) eklemeniz gerekir:

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

Compose'da ConstraintLayout bir DSL kullanıldığında şu ş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'a yönelik sınırlamaları belirtmek için kullanılabilecek mevcut bir referanstır.

ConstraintLayout kullanan bir composable örneğini burada 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 üst kısmını 16.dp ve Button alt kısmındaki Text kenarla 16.dp kenarla üst öğe ile sınırlandırır.

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. Ancak kısıtlamaları, uygulandıkları düzenlerden ayırmanın tercih edildiği durumlar vardır. Örneğin, ekran yapılandırmasına göre kısıtlamaları değiştirmek veya iki kısıtlama kümesi arasında animasyon uygulamak isteyebilirsiniz.

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

  1. ConstraintLayout öğesine parametre olarak bir ConstraintSet iletin.
  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ızın içindeki öğelerin konumlandırılmasına yardımcı olabilecek kurallar, bariyerler ve zincirler gibi kavramlar içerir.

Kurallar

Yönergeler, düzenleri tasarlamak için kullanabileceğiniz küçük görsel yardımcılardır. Oluşturulabilirler bir yönergeyle sınırlandırılabilir. Kurallar, öğelerin üst composable'ın içinde belirli bir dp veya percentage konumuna yerleştirilmesi için faydalıdır.

Dikey ve yatay olmak üzere iki farklı kural 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)
}

Yönerge oluşturmak için gerekli yönerge türüyle createGuidelineFrom* kullanın. Bu işlem, Modifier.constrainAs() blokunda kullanılabilecek bir referans oluşturur.

Bariyerler

Bariyerler, belirtilen taraftaki en uç widget'a dayalı sanal bir kural oluşturmak için birden fazla composable'a başvurur.

Bariyer oluşturmak için createTopBarrier() (veya createBottomBarrier(), createEndBarrier(), createStartBarrier()) etiketlerini kullanın ve engeli oluşturması gereken referansları belirtin.

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

        val topBarrier = createTopBarrier(button, text)
    }
}

Bariyer daha sonra bir Modifier.constrainAs() blokta kullanılabilir.

Zincirler

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

Zincir oluşturmak için createVerticalChain veya createHorizontalChain tuşlarını 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() blokunda kullanılabilir.

Zincir, farklı ChainStyles ile yapılandırılabilir. Bu yapılandırma, bir composable'ın çevresindeki alanla nasıl işlem yapılacağına karar verir. Örneğin:

  • ChainStyle.Spread: Alan, ilk composable'dan önceki ve son composable'dan sonraki boş alan da dahil olmak üzere tüm composable'lara eşit olarak dağıtılır.
  • ChainStyle.SpreadInside: Alan, tüm composable'lar arasında eşit olarak dağıtılır. İlk composable'dan önce ya da son composable'dan sonra boşluk kullanılamaz.
  • ChainStyle.Packed: Alan, ilk composable'dan önce ve son composable'dan sonra dağıtılır. composable'lar, aralarında boşluk kalmayacak şekilde paketlenir.

Daha fazla bilgi

ConstraintLayout kullanan oluşturma örneklerinden yararlanarak API'lerin Compose'da ConstraintLayout kullanımı hakkında daha fazla bilgi edinin.