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

Compose'un kurallarından biri, alt öğelerinizi yalnızca bir kez ölçmeniz gerektiğidir. Alt öğeleri iki kez ölçmek, çalışma zamanı istisnası oluşturur. Ancak, ölçüm yapmadan önce çocuklarınız hakkında bazı bilgilere ihtiyacınız 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örüntülemek 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'nin minIntrinsicHeight'sını sorarsanız Text'nin height'ını tek satırda çizilmiş metinle birlikte döndürür.

Yerleşik özelliklerin çalışma şekli

Ekranda iki metni ayırıcıyla ayırarak gösteren bir composable oluşturabilirsiniz:

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

Bunu yapmak için, mevcut alanı dolduran iki Text composable'ı ve ortada bir Divider içeren bir Row kullanın. 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
        )
    }
}

Divider, istenen davranış olmamasına rağmen tüm ekrana genişliyor:

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üğünden ve Text yüksekliğinin Divider öğesini sınırlamak için kullanılamamasıdır.

Divider öğesinin, kullanılabilir alanı belirli bir yükseklikle doldurmasını istiyorsanız height(IntrinsicSize.Min) değiştiricisini kullanın.

height(IntrinsicSize.Min), alt öğelerini minimum doğal yükseklikleri kadar yüksek olacak şekilde boyutlandırır. Bu değiştirici yinelemeli olduğundan Row ve alt öğelerinin minIntrinsicHeight öğesini sorgular.

Bu değiştiriciyi kodunuza uyguladığınızda kodunuz 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 yüksekliği aşağıdaki şekilde belirlenir:

  • Row composable'ın minIntrinsicHeight değeri, alt öğelerinin maksimum minIntrinsicHeight değeridir.
  • Kısıtlama verilmediği için yer kaplamadığından Divider öğesinin minIntrinsicHeight değeri 0'dır.
  • Text minIntrinsicHeight, belirli bir width için metnin Text minIntrinsicHeight'idir.
  • Bu nedenle, Row öğesinin height kısıtlaması, Text öğelerinin maksimum minIntrinsicHeight değeri olur.
  • Divider, height değerini Row tarafından verilen height kısıtlamasına göre genişletir.

Özel düzenlerinizdeki intrinsikler

Özel bir Layout veya layout değiştirici oluştururken, içsel ölçümler yaklaşık değerlere göre otomatik olarak 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çümlerini belirtmek için oluştururken MeasurePolicy arayüzünün minIntrinsicWidth, minIntrinsicHeight, maxIntrinsicWidth ve maxIntrinsicHeight değerlerini geçersiz kılın.

@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 layout arayüzündeki ilgili yöntemleri geçersiz kılın.LayoutModifier

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.
}