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

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

«درون‌گرها» به شما امکان می‌دهد کودکان را قبل‌از اینکه واقعاً اندازه‌گیری شوند، پُرسمان کنید.

برای عنصر ترکیبی، می‌توانید 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 درحال اقدام

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

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

برای انجام این کار، از 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.
}