Compose düzenlerindeki içsel ölçümler

Compose'un kurallarından biri, çocuklarınızı yalnızca bir kez ölçmeniz gerektiğidir. Çocukları iki kez ölçmek, çalışma zamanı istisnası oluşturur. Ancak, çocuklarınızın ölçülerini almadan önce haklarında bilgi edinmeniz gereken durumlar olabilir.

Intrinsics, çocuklar ölçülmeden önce onlarla ilgili sorgu yapmanıza olanak tanır.

Bir composable'ın IntrinsicSize.Min veya IntrinsicSize.Max değerini isteyebilirsiniz:

  • Modifier.width(IntrinsicSize.Min) - İçeriğinizi düzgün şekilde göstermek için gereken minimum genişlik nedir?
  • Modifier.width(IntrinsicSize.Max) - İçeriğinizi düzgün şekilde görüntülemek için gereken maksimum genişlik nedir?
  • Modifier.height(IntrinsicSize.Min) - İçeriğinizi düzgün şekilde göstermek için gereken minimum yükseklik nedir?
  • Modifier.height(IntrinsicSize.Max) - İçeriğinizi düzgün şekilde göstermek için gereken maksimum yükseklik nedir?

Örneğin, özel bir düzende sonsuz width kısıtlaması olan bir Text öğesinin minIntrinsicHeight özelliğini sorarsanız metnin tek bir satırda çizildiği Text öğesinin height özelliğini döndürür.

Yerleşik özelliklerin kullanımı

Ekranda iki metni aşağıdaki gibi bir ayırıcıyla ayırarak gösteren bir composable oluşturmak istediğimizi düşünelim:

Yan yana iki metin öğesi ve aralarında dikey bir ayırıcı

Bunu nasıl yapabiliriz? İçinde iki Text bulunan ve olabildiğince genişleyen bir Row ile ortada bir Divider olabilir. Divider, en uzun Text kadar uzun ve ince (width = 1.dp) olmalıdır.

@Composable
fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) {
    Row(modifier = modifier) {
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(start = 4.dp)
                .wrapContentWidth(Alignment.Start),
            text = text1
        )
        VerticalDivider(
            color = Color.Black,
            modifier = Modifier.fillMaxHeight().width(1.dp)
        )
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(end = 4.dp)
                .wrapContentWidth(Alignment.End),

            text = text2
        )
    }
}

Bunu önizlediğimizde Divider öğesinin tüm ekranı kapladığını görüyoruz. Bu, istediğimiz bir durum değil:

Yan yana iki metin öğesi ve aralarında bir ayırıcı var ancak ayırıcı, metnin alt kısmının altına kadar uzanıyor.

Bunun nedeni, Row her alt öğeyi ayrı ayrı ölçtüğü ve Text yüksekliğinin Divider öğesini sınırlamak için kullanılamamasıdır. Divider öğesinin, mevcut alanı belirli bir yükseklikle doldurmasını istiyoruz. Bunun için height(IntrinsicSize.Min) değiştiricisini kullanabiliriz .

height(IntrinsicSize.Min), alt öğelerini minimum doğal yükseklikleri kadar yüksek olmaya zorlar. Özyinelemeli olduğundan Row ve alt öğeleri minIntrinsicHeight sorgulanır.

Bunu kodumuza uyguladığımızda beklendiği gibi çalışır:

@Composable
fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) {
    Row(modifier = modifier.height(IntrinsicSize.Min)) {
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(start = 4.dp)
                .wrapContentWidth(Alignment.Start),
            text = text1
        )
        VerticalDivider(
            color = Color.Black,
            modifier = Modifier.fillMaxHeight().width(1.dp)
        )
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(end = 4.dp)
                .wrapContentWidth(Alignment.End),

            text = text2
        )
    }
}

// @Preview
@Composable
fun TwoTextsPreview() {
    MaterialTheme {
        Surface {
            TwoTexts(text1 = "Hi", text2 = "there")
        }
    }
}

Önizlemeli:

Yan yana iki metin öğesi ve aralarında dikey bir ayırıcı

Row composable'ın minIntrinsicHeight değeri, alt öğelerinin minIntrinsicHeight değerinin maksimumu olur. Divider öğesinin minIntrinsicHeight değeri 0'dır. Çünkü kısıtlama verilmediğinde alan kaplamaz. Text minIntrinsicHeight değeri ise belirli bir width değeri verilen metnin değeri olur. Bu nedenle, Row öğesinin height kısıtlaması, Text değerlerinin maksimum minIntrinsicHeight değeri olur. Divider, Row tarafından verilen height kısıtlamasıyla height değerini genişletir.

Özel düzenlerinizdeki dahili öğeler

Özel bir Layout veya layout değiştiricisi oluştururken, yaklaşık değerlere göre otomatik olarak içsel ölçümler hesaplanır. Bu nedenle, hesaplamalar tüm düzenler için doğru olmayabilir. Bu API'ler, bu varsayılanları geçersiz kılma seçenekleri sunar.

Özel Layout öğenizin içsel ölçülerini belirtmek için Layout öğesini oluştururken minIntrinsicWidth, minIntrinsicHeight, maxIntrinsicWidth ve maxIntrinsicHeight arayüzünü geçersiz kılın.MeasurePolicy

@Composable
fun MyCustomComposable(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        content = content,
        modifier = modifier,
        measurePolicy = object : MeasurePolicy {
            override fun MeasureScope.measure(
                measurables: List<Measurable>,
                constraints: Constraints
            ): MeasureResult {
                // Measure and layout here
                // ...
            }

            override fun IntrinsicMeasureScope.minIntrinsicWidth(
                measurables: List<IntrinsicMeasurable>,
                height: Int
            ): Int {
                // Logic here
                // ...
            }

            // Other intrinsics related methods have a default value,
            // you can override only the methods that you need.
        }
    )
}

Özel layout değiştiricinizi oluştururken LayoutModifier arayüzündeki ilgili yöntemleri geçersiz kılın.

fun Modifier.myCustomModifier(/* ... */) = this then object : LayoutModifier {

    override fun MeasureScope.measure(
        measurable: Measurable,
        constraints: Constraints
    ): MeasureResult {
        // Measure and layout here
        // ...
    }

    override fun IntrinsicMeasureScope.minIntrinsicWidth(
        measurable: IntrinsicMeasurable,
        height: Int
    ): Int {
        // Logic here
        // ...
    }

    // Other intrinsics related methods have a default value,
    // you can override only the methods that you need.
}