اندازه‌گیری‌های ذاتی در چیدمان‌های «نوشتن»

یکی از قوانین Compose این است که باید فرزندان خود را فقط یک بار اندازه‌گیری کنید؛ اندازه‌گیری فرزندان دو بار یک استثنای زمان اجرا ایجاد می‌کند. اما گاهی اوقات پیش‌از اندازه‌گیری کودکان، به اطلاعاتی درباره آن‌ها نیاز دارید.

Intrinsics به شما امکان می‌دهد قبل‌از اندازه‌گیری واقعی فرزندان، از آن‌ها پرس‌وجو کنید.

برای یک composable، می‌توانید IntrinsicSize.Min یا IntrinsicSize.Max آن را درخواست کنید:

  • Modifier.width(IntrinsicSize.Min) - حداقل عرضی که برای نمایش درست محتوایتان نیاز دارید چقدر است؟
  • Modifier.width(IntrinsicSize.Max) - حداکثر عرضی که برای نمایش درست محتوایتان نیاز دارید چقدر است؟
  • Modifier.height(IntrinsicSize.Min) - حداقل ارتفاعی که برای نمایش درست محتوایتان نیاز دارید چقدر است؟
  • Modifier.height(IntrinsicSize.Max) - حداکثر ارتفاعی که برای نمایش درست محتوایتان نیاز دارید چقدر است؟

برای مثال، اگر minIntrinsicHeight Text را با محدودیت‌های بی‌نهایت width در چیدمان سفارشی درخواست کنید، height Text را با نوشتار ترسیم‌شده در یک خط برمی‌گرداند.

Intrinsics در عمل

می‌توانید یک composable ایجاد کنید که دو نوشتار را روی صفحه نمایش دهد که با یک جداکننده از هم جدا شده‌اند:

دو عنصر نوشتاری در کنار هم، با یک جداکننده عمودی بین آن‌ها

برای انجام این کار، از Row با دو Text ترکیب‌پذیر که فضای دردسترس را پر می‌کنند، و Divider در وسط استفاده کنید. Divider باید به بلندی بلندترین Text باشد و باید باریک (width = 1.dp) باشد.

@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 به کل صفحه گسترش می‌یابد که رفتار مطلوب نیست:

دو عنصر نوشتاری در کنار هم، با یک جداکننده بین آن‌ها، اما جداکننده تا زیر پایین نوشتار کشیده شده است

این اتفاق می‌افتد زیرا Row هر فرزند را به‌طور جداگانه اندازه‌گیری می‌کند و از ارتفاع Text نمی‌توان برای محدود کردن Divider استفاده کرد.

برای اینکه Divider فضای دردسترس را با ارتفاع مشخصی پر کند، از اصلاح‌کننده height(IntrinsicSize.Min) استفاده کنید.

height(IntrinsicSize.Min) اندازه فرزندانش را به‌اندازه حداقل ارتفاع ذاتی‌شان تعیین می‌کند. چون این اصلاح‌کننده بازگشتی است، minIntrinsicHeight مربوط به Row و فرزندان آن را پرسمان می‌کند.

اعمال این اصلاح‌کننده به کدتان باعث می‌شود طبق انتظار کار کند:

@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")
        }
    }
}

با پیش‌نمایش:

دو عنصر نوشتاری در کنار هم، با یک جداکننده عمودی بین آن‌ها

ارتفاع Row به‌صورت زیر تعیین می‌شود:

  • minIntrinsicHeight ترکیب‌پذیر Row حداکثر minIntrinsicHeight فرزندان آن است.
  • minIntrinsicHeight عنصر Divider برابر با ۰ است، زیرا اگر هیچ محدودیتی داده نشود، فضایی را اشغال نمی‌کند.
  • Text minIntrinsicHeight مربوط به نوشتار برای width خاصی است.
  • بنابراین، محدودیت height عنصر Row به حداکثر minIntrinsicHeight Text تبدیل می‌شود.
  • سپس Divider height خود را به محدودیت height ارائه‌شده توسط Row گسترش می‌دهد.

ویژگی‌های ذاتی در چیدمان‌های سفارشی شما

هنگام ایجاد اصلاح‌کننده سفارشی Layout یا layout، اندازه‌گیری‌های ذاتی به‌طور خودکار براساس تقریب‌ها محاسبه می‌شوند. بنابراین، ممکن است محاسبات برای همه چیدمان‌ها درست نباشد. این میاناهای برنامه‌سازی کاربردی گزینه‌هایی برای لغو این پیش‌فرض‌ها ارائه می‌دهند.

برای مشخص کردن اندازه‌گیری‌های ذاتی Layout سفارشی‌تان، minIntrinsicWidth، minIntrinsicHeight، maxIntrinsicWidth، و maxIntrinsicHeight میانای 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.
        }
    )
}

هنگام ایجاد اصلاح‌کننده سفارشی layout، روش‌های مرتبط را در میانای 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.
}