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

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

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

برای یک کامپوزیشن، می توانید intrinsicWidth یا intrinsicHeight درونی آن را بخواهید:

  • (min|max)IntrinsicWidth : با توجه به این عرض، حداقل/حداکثر عرضی که می توانید محتوای خود را به درستی نقاشی کنید چقدر است؟
  • (min|max)IntrinsicHeight : با توجه به این ارتفاع، حداقل/حداکثر ارتفاعی که می توانید محتوای خود را به درستی نقاشی کنید چقدر است؟

به عنوان مثال، اگر از minIntrinsicHeight یک Text با height بی نهایت بپرسید، 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
        )
        HorizontalDivider(
            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) اندازه فرزندانش را می دهد که مجبور می شوند به اندازه حداقل قد ذاتی خود قد داشته باشند. از آنجایی که بازگشتی است، Row و فرزندان آن minIntrinsicHeight پرس و جو می کند.

با اعمال آن در کد ما، همانطور که انتظار می رود کار می کند:

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

با پیش نمایش:

دو عنصر متنی در کنار هم، با یک تقسیم کننده عمودی بین آنها

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

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