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

Compose'un kurallarından biri, alt öğeleri yalnızca bir kez ölçmenizdir. Alt öğeleri iki kez ölçmek, çalışma zamanı istisnasına yol açar. Bununla birlikte, çocuklarınızı ölçmeden önce bazı bilgilere ihtiyaç duyduğunuz zamanlar olabilir.

Doğal nitelik, çocukları gerçekte ölçülmeden önce sorgulamanızı sağlar.

Bir composable için intrinsicWidth veya intrinsicHeight isteyebilirsiniz:

  • (min|max)IntrinsicWidth: Bu genişliğe göre, içeriğinizi düzgün şekilde boyayabileceğiniz minimum/maksimum genişlik nedir?
  • (min|max)IntrinsicHeight: Bu yükseklik göz önüne alındığında, içeriğinizi düzgün şekilde boyayabileceğiniz minimum/maksimum yükseklik nedir?

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

Yerleşik özellikleri uygulama

Ekranda iki metni şu şekilde bir ayırıcıyla ayrılmış olarak gösteren bir composable oluşturmak istediğimizi hayal edin:

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

Bunu nasıl yapabiliriz? İçinde mümkün olduğunca geniş olan iki Text ve ortasında bir Divider bulunan bir Row olabilir. Divider öğesinin, en uzun Text ve 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 Divider öğesinin tüm ekrana genişlediğini görürüz ve bizim istediğimiz bu değildir:

Yan yana duran iki metin öğesi, aralarında ayırıcı var. Ancak ayırıcı metnin alt kısmına doğru uzanıyor

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

height(IntrinsicSize.Min), çocuklarının doğal boylarını aşmaya zorlanır. Yinelemeli olduğundan Row ve alt öğelerini (minIntrinsicHeight) sorgular.

Bu kodu kodumuza uyguladığınızda, beklendiği gibi çalışacaktı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 composable'ın minIntrinsicHeight, alt öğelerinin maksimum minIntrinsicHeight tanesi olacak. Divider öğesinin minIntrinsicHeight değeri, herhangi bir kısıtlama sağlanmadığında yer kaplamadığı için 0 olur. Text minIntrinsicHeight değeri, belirli bir width belirtilen metin olur. Bu nedenle, Row öğesinin height kısıtlaması, Text için maksimum minIntrinsicHeight olacaktır. Daha sonra Divider, height değerini Row tarafından sağlanan height kısıtlamasına genişletir.

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

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

Özel Layout'inizin yerleşik ölçümlerini belirtmek için arayüz 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 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.
}