خطوط المحاذاة في Jetpack Compose

يتيح لك نموذج تنسيق الإنشاء استخدام AlignmentLine لإنشاء محتوى مخصّص خطوط محاذاة يمكن استخدامها بواسطة التخطيطات الرئيسية لمحاذاة ووضعها الأطفال. على سبيل المثال، يمكن لعنصر Row استخدام خطوط المحاذاة المخصّصة لعناصره الفرعية لمحاذاتها.

عندما يقدّم تنسيق قيمة لعنصر AlignmentLine معيّن، يمكن للعناصر الرئيسية للتنسيق قراءة هذه القيمة بعد القياس، باستخدام عامل التشغيل Placeable.get في مثيل Placeable المقابل. استنادًا إلى منصب AlignmentLine، يمكن للوالدَين ثم تحديد مكانة الأطفال.

تأتي بعض العناصر القابلة للإنشاء في Compose مع خطوط المحاذاة. على سبيل المثال، 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 مكوّنًا مخصّصًا يعرض خطَّي ALIGNED، MaxChartValue وMinChartValue، لكي تتمكّن العناصر المكوّنة الأخرى من ALIGNED مع الحد الأقصى والحد الأدنى لقيمة البيانات في الرسم البياني. تمّت محاذاة عنصرَي النص الحدّ الأقصى والحدّ الأدنى في منتصف خطوط المحاذاة المخصّصة.

الشكل 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)
        )
    }
}

ما من اقتراحات في الوقت الحالي.

يُرجى محاولة إلى حسابك على Google.