يتيح لك نموذج التصميم "إنشاء" استخدام AlignmentLine
لإنشاء أسطر محاذاة مخصّصة يمكن استخدامها من خلال التنسيقات الرئيسية لمحاذاة العناصر الثانوية وتحديد موقعها. على سبيل المثال،
Row
يمكن أن يستخدم أسطر المحاذاة المخصصة للأطفال لمحاذاة هذه الخطوط.
عندما يوفّر التنسيق قيمة لسمة AlignmentLine
معيّنة، يمكن للوالدَين
تنسيق هذه القيمة بعد قياسها، وذلك باستخدام عامل التشغيل Placeable.get
على مثيل
Placeable
المقابل.
وبناءً على موضع AlignmentLine
، يمكن للوالدَين تحديد موضع الأطفال.
بعض العناصر القابلة للإنشاء في ميزة "الإنشاء" تأتي مع أسطر محاذاة. على سبيل المثال، تعرض BasicText
القابلة للدمج سطرَي المحاذاة FirstBaseline
وLastBaseline
.
في المثال أدناه، يقرأ رمز LayoutModifier
المخصّص باسم
firstBaselineToTop
FirstBaseline
لإضافة مساحة متروكة إلى Text
بدءًا من المرجع الأساسي.
الشكل 1. يعرض الفرق بين إضافة مساحة متروكة عادية إلى عنصر وإضافة مساحة متروكة إلى المرجع الأساسي.
fun Modifier.firstBaselineToTop( firstBaselineToTop: Dp, ) = layout { measurable, constraints -> // Measure the composable val placeable = measurable.measure(constraints) // Check the composable has a first baseline check(placeable[FirstBaseline] != AlignmentLine.Unspecified) val firstBaseline = placeable[FirstBaseline] // Height of the composable with padding - first baseline val placeableY = firstBaselineToTop.roundToPx() - firstBaseline val height = placeable.height + placeableY layout(placeable.width, height) { // Where the composable gets placed placeable.placeRelative(0, placeableY) } } @Preview @Composable private fun TextWithPaddingToBaseline() { MaterialTheme { Text("Hi there!", Modifier.firstBaselineToTop(32.dp)) } }
لقراءة FirstBaseline
في المثال،
يتم استخدام placeable [FirstBaseline]
في مرحلة القياس.
إنشاء أسطر محاذاة مخصَّصة
عند إنشاء عنصر Layout
مخصّص أو مخصّص LayoutModifier
، يمكنك توفير أسطر محاذاة مخصّصة بحيث يمكن لتلك العناصر الرئيسية الأخرى استخدامها لمحاذاة العناصر الثانوية وتحديد موضعها وفقًا لذلك.
يوضّح المثال التالي تركيبة BarChart
مخصّصة تكشف عن خطَي محاذاة، MaxChartValue
وMinChartValue
، بحيث يمكن محاذاة العناصر القابلة للتجميع مع الحد الأقصى والحد الأدنى لقيمة بيانات الرسم البياني. تمت محاذاة عنصرَي نص، الحد الأقصى والحد الأدنى، في وسط خطوط المحاذاة المخصصة.
الشكل 2: BarChart
قابلة للدمج مع النص تتوافق مع الحد الأقصى والحد الأدنى لقيمة البيانات.
يتم تحديد خطوط المحاذاة المخصصة كمتغيرات مستوى أعلى في مشروعك.
/** * AlignmentLine defined by the maximum data value in a [BarChart] */ private val MaxChartValue = HorizontalAlignmentLine(merger = { old, new -> min(old, new) }) /** * AlignmentLine defined by the minimum data value in a [BarChart] */ private val MinChartValue = HorizontalAlignmentLine(merger = { old, new -> max(old, new) })
أسطر المحاذاة المخصّصة لإنشاء المثال هي من النوع
HorizontalAlignmentLine
، حيث
يتم استخدامها لمحاذاة الأطفال عموديًا. يتم تمرير سياسة الدمج كمَعلمة
في حال كانت هناك تنسيقات متعددة توفّر قيمة لخطوط المحاذاة هذه. بما أن إحداثيات نظام الإنشاء وإحداثيات Canvas
تمثّل [0, 0]
، فإنّ الزاوية العلوية اليسرى والمحور x
وy
إيجابيان، وبالتالي ستصبح قيمة MaxChartValue
دائمًا أقل من
MinChartValue
. ولذلك، تتمثل سياسة الدمج في min
بالنسبة إلى المرجع الأساسي لقيمة بيانات الرسم البياني، وmax
للحد الأدنى لقيمة قيمة بيانات الرسم البياني.
عند إنشاء Layout
أو LayoutModifier
مخصّصَين، حدِّد أسطر المحاذاة المخصّصة في الإجراء MeasureScope.layout
،
والتي تستغرق معلَمة alignmentLines: Map<AlignmentLine, Int>
.
@Composable private fun BarChart( dataPoints: List<Int>, modifier: Modifier = Modifier, ) { val maxValue: Float = remember(dataPoints) { dataPoints.maxOrNull()!! * 1.2f } BoxWithConstraints(modifier = modifier) { val density = LocalDensity.current with(density) { // ... // Calculate baselines val maxYBaseline = // ... val minYBaseline = // ... Layout( content = {}, modifier = Modifier.drawBehind { // ... } ) { _, constraints -> with(constraints) { layout( width = if (hasBoundedWidth) maxWidth else minWidth, height = if (hasBoundedHeight) maxHeight else minHeight, // Custom AlignmentLines are set here. These are propagated // to direct and indirect parent composables. alignmentLines = mapOf( MinChartValue to minYBaseline.roundToInt(), MaxChartValue to maxYBaseline.roundToInt() ) ) {} } } } } }
يمكن للوالدَين مباشرةً وغير مباشرتَين على هذه النسخة أن يستهلكا خطوط المحاذاة. ينشئ العنصر التالي القابل للإنشاء تنسيقًا مخصّصًا يُستخدَم
كمعلّمَتَين مع Text
نقطتَي بيانات، كما يعمل على محاذاة النصَّين مع
الحد الأقصى والحد الأدنى لقيم بيانات الرسم البياني. تظهر معاينة هذه التركيبة
في الشكل 2.
@Composable private fun BarChartMinMax( dataPoints: List<Int>, maxText: @Composable () -> Unit, minText: @Composable () -> Unit, modifier: Modifier = Modifier, ) { Layout( content = { maxText() minText() // Set a fixed size to make the example easier to follow BarChart(dataPoints, Modifier.size(200.dp)) }, modifier = modifier ) { measurables, constraints -> check(measurables.size == 3) val placeables = measurables.map { it.measure(constraints.copy(minWidth = 0, minHeight = 0)) } val maxTextPlaceable = placeables[0] val minTextPlaceable = placeables[1] val barChartPlaceable = placeables[2] // Obtain the alignment lines from BarChart to position the Text val minValueBaseline = barChartPlaceable[MinChartValue] val maxValueBaseline = barChartPlaceable[MaxChartValue] layout(constraints.maxWidth, constraints.maxHeight) { maxTextPlaceable.placeRelative( x = 0, y = maxValueBaseline - (maxTextPlaceable.height / 2) ) minTextPlaceable.placeRelative( x = 0, y = minValueBaseline - (minTextPlaceable.height / 2) ) barChartPlaceable.placeRelative( x = max(maxTextPlaceable.width, minTextPlaceable.width) + 20, y = 0 ) } } } @Preview @Composable private fun ChartDataPreview() { MaterialTheme { BarChartMinMax( dataPoints = listOf(4, 24, 15), maxText = { Text("Max") }, minText = { Text("Min") }, modifier = Modifier.padding(24.dp) ) } }