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

Oluşturma kurallarından biri, alt öğelerinizi yalnızca bir kez ölçmenizdir; alt öğeleri iki kez ölçmek, çalışma zamanı istisnasına neden olur. Bununla birlikte, ölçümden önce çocuklarınızla ilgili bazı bilgilere ihtiyaç duyduğunuz zamanlar vardır.

Intrinsics, çocukları ölçülmeden önce sorgulamanıza olanak tanır.

Bir beste için intrinsicWidth veya intrinsicHeight isteyebilirsiniz:

  • (min|max)IntrinsicWidth: Bu yüksekliği göz önünde bulundurduğunuzda, içeriğinizi düzgün şekilde boyayabileceğiniz minimum/maksimum genişlik nedir?
  • (min|max)IntrinsicHeight: Bu genişliğe dayanarak, içeriğinizi uygun şekilde boyayabileceğiniz minimum/maksimum yükseklik nedir?

Örneğin, sonsuz width içeren bir Text öğesinin minIntrinsicHeight değerini sorarsanız Text öğesinin height değerini, metin tek bir satır halinde çizilmiş gibi döndürür.

Doğal gücün işleyiş şekli

Ekranda, aşağıdaki gibi ayırıcıyla ayrılmış iki metin görüntüleyen bir kompozisyon oluşturmak istediğinizi varsayalım:

Aralarında dikey ayırıcı bulunan yan yana iki metin öğesi

Bunu nasıl yapabiliriz? İçinde mümkün olduğunca genişleyen iki Text ve ortasında bir Divider olan bir Row olabilir. Ayırıcı'nın en yüksek Text ve en ince (width = 1.dp) kadar uzun olmasını istiyoruz.

@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
        )
        Divider(
            color = Color.Black,
            modifier = Modifier.fillMaxHeight().width(1.dp)
        )
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(end = 4.dp)
                .wrapContentWidth(Alignment.End),

            text = text2
        )
    }
}

Bunu önizlersek, Ayırıcı'nın tüm ekrana genişlediğini görürüz ve istediğimiz şey bu değildir:

İki metin öğesi, aralarında bir ayırıcı bulunan yan yana ancak ayırıcı metnin alt kısmına doğru uzanıyor

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

height(IntrinsicSize.Min), çocuklarını en az doğuştan gelen boyu kadar uzun kalmaya zorlayan çocukların boyutlarını seçer. Yinelemeli olduğundan Row ve alt öğelerini minIntrinsicHeight sorgular.

Bu komut, kodumuza uygulandığında 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
        )
        Divider(
            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")
        }
    }
}

Önizlemeyle:

Aralarında dikey ayırıcı bulunan yan yana iki metin öğesi

Row bestesinin minIntrinsicHeight öğesi, alt öğeleri arasından maksimum minIntrinsicHeight öğe olacak. Divider öğesinin minIntrinsicHeight değeri, hiçbir kısıtlama belirtilmediğinde yer kaplamadığı için 0'dır. Text minIntrinsicHeight değeri, belirli bir width değeri verilen metne ait olacaktır. Bu nedenle, Row öğesinin height kısıtlaması, Text değerlerinin maksimum minIntrinsicHeight değeri olur. Divider, daha sonra height öğesini Row tarafından belirtilen height kısıtlamasına genişletir.

Özel düzenlarınızdaki içsel öğeler

Özel bir Layout veya layout değiştiricisi 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 MeasurePolicy arayüzünü oluştururken 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 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.
}