اندازه‌گیری‌های ذاتی در طرح‌بندی‌های Compose

یکی از قوانین 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 را با متن کشیده شده در یک خط واحد برمی‌گرداند.

عناصر ذاتی در عمل

شما می‌توانید یک 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 composable، حداکثر minIntrinsicHeight فرزندان آن است.
  • minIntrinsicHeight عنصر Divider برابر با ۰ است، زیرا اگر هیچ محدودیتی تعیین نشود، فضایی را اشغال نمی‌کند.
  • minIntrinsicHeight Text ، مربوط به یک width خاص است.
  • بنابراین، قید height عنصر Row به حداکثر minIntrinsicHeight مربوط به Text تبدیل می‌شود.
  • سپس Divider height خود را به محدودیت height که توسط Row داده شده است، افزایش می‌دهد.

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

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

برای مشخص کردن اندازه‌های ذاتی Layout سفارشی خود، هنگام ایجاد رابط MeasurePolicy مقادیر minIntrinsicWidth ، minIntrinsicHeight ، maxIntrinsicWidth و maxIntrinsicHeight را بازنویسی کنید.

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

{% کلمه به کلمه %} {% فعل کمکی %} {% کلمه به کلمه %} {% فعل کمکی %}