یکی از قوانین 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حداکثرminIntrinsicHeightفرزندانش است.minIntrinsicHeightعنصرDividerبرابر با ۰ است، زیرا اگر محدودیتی داده نشود، فضایی را اشغال نمیکند.TextminIntrinsicHeightمربوط به نوشتار برایwidthخاصی است.- بنابراین، محدودیت
heightعنصرRowبه حداکثرminIntrinsicHeightTextتبدیل میشود. - سپس
Dividerheightخود را به محدودیتheightکه توسطRowارائه شده است گسترش میدهد.
ویژگیهای ذاتی در چیدمانهای سفارشی شما
هنگام ایجاد اصلاحکننده سفارشی Layout یا layout، اندازهگیریهای ذاتی
بهطور خودکار براساس تقریبها محاسبه میشوند. بنابراین، ممکن است محاسبات برای همه چیدمانها درست نباشد. این میاناهای برنامهسازی کاربردی گزینههایی
برای لغو این پیشفرضها ارائه میدهند.
برای مشخص کردن اندازهگیریهای ذاتی Layout سفارشیتان،
minIntrinsicWidth، minIntrinsicHeight، maxIntrinsicWidth، و
maxIntrinsicHeight میانای MeasurePolicy را هنگام ایجاد آن لغو کنید.
لغو شما باید با آنچه measure انجام میدهد مطابقت داشته باشد. For example, in a custom
column that stacks its children vertically and gives each child the full column
width, the minimum intrinsic height for a given width is the sum of its
children's minimum intrinsic heights for that width:
@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 { val childConstraints = constraints.copy(minHeight = 0) val placeables = measurables.map { measurable -> measurable.measure(childConstraints) } val width = constraints.constrainWidth( placeables.maxOfOrNull { it.width } ?: 0 ) val height = constraints.constrainHeight( placeables.sumOf { it.height } ) return layout(width, height) { var yPosition = 0 placeables.forEach { placeable -> placeable.placeRelative(x = 0, y = yPosition) yPosition += placeable.height } } } override fun IntrinsicMeasureScope.minIntrinsicHeight( measurables: List<IntrinsicMeasurable>, width: Int ): Int { return measurables.sumOf { measurable -> measurable.minIntrinsicHeight(width) } } // Other intrinsics related methods have a default value, // you can override only the methods that you need. } ) }
هنگام ایجاد اصلاحکننده سفارشی layout، روشهای مرتبط را در میانای LayoutModifier لغو کنید. محاسبه ذاتی باید با
measure مطابقت داشته باشد. برای مثال، برای یک height مشخص، اصلاحکنندهای که حاشیه داخلی ثابتی را به همه طرفها اضافه میکند، حاشیه داخلی عمودی را قبلاز پرسمان minIntrinsicWidth فرزند کم میکند و حاشیه داخلی افقی را به نتیجه اضافه میکند:
fun Modifier.myCustomModifier(padding: Dp = 8.dp) = this then object : LayoutModifier { override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints ): MeasureResult { val paddingPx = padding.roundToPx() val horizontal = paddingPx * 2 val vertical = paddingPx * 2 val placeable = measurable.measure( constraints.offset(-horizontal, -vertical) ) val width = constraints.constrainWidth(placeable.width + horizontal) val height = constraints.constrainHeight(placeable.height + vertical) return layout(width, height) { placeable.place(paddingPx, paddingPx) } } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurable: IntrinsicMeasurable, height: Int ): Int { val paddingPx = padding.roundToPx() val horizontal = paddingPx * 2 val vertical = paddingPx * 2 val childHeight = if (height == Constraints.Infinity) { Constraints.Infinity } else { (height - vertical).coerceAtLeast(0) } return measurable.minIntrinsicWidth(childHeight) + horizontal } // Other intrinsics related methods have a default value, // you can override only the methods that you need. }
توصیهشده برای شما
- توجه: وقتی جاوا اسکریپت خاموش باشد، نوشتار پیوند نمایش داده میشود
- چیدمانهای سفارشی {:#custom-layouts}
- خطوط تراز در Jetpack Compose
- فازهای Jetpack Compose