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

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

Intrinsics به شما این امکان را می‌دهد تا قبل از اینکه بچه‌ها واقعاً اندازه‌گیری شوند، سؤال کنید.

برای یک Composable، می توانید IntrinsicSize.Min یا IntrinsicSize.Max آن را بخواهید:

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

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

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

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

برای تعیین اندازه‌گیری‌های داخلی 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.
}

{% کلمه به کلمه %} {% آخر کلمه %} {% کلمه به کلمه %} {% آخر کلمه %}