خطوط تراز در Jetpack Compose

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

هنگامی که یک طرح بندی مقداری را برای یک AlignmentLine خاص ارائه می کند، والدین طرح بندی می توانند این مقدار را پس از اندازه گیری با استفاده از عملگر Placeable.get در نمونه Placeable مربوطه بخوانند. بر اساس موقعیت AlignmentLine ، والدین می توانند در مورد موقعیت فرزندان تصمیم بگیرند.

برخی از composable ها در Compose از قبل با خطوط تراز ارائه می شوند. برای مثال، BasicText قابل ترکیب خطوط تراز FirstBaseline و LastBaseline را در معرض دید قرار می دهد.

در مثال زیر، یک LayoutModifier سفارشی به نام firstBaselineToTop FirstBaseline را می‌خواند تا از اولین خط پایه، به Text اضافه کند.

شکل 1. تفاوت بین افزودن padding معمولی به یک عنصر و اعمال padding به خط پایه عنصر Text را نشان می دهد.

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 composable سفارشی یا 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 هستند، زیرا از آنها برای تراز کردن عمودی کودکان استفاده می شود. یک خط مشی ادغام به عنوان یک پارامتر در صورتی که طرح‌بندی‌های متعدد مقداری برای این خطوط تراز ارائه می‌کنند، ارسال می‌شود. همانطور که مختصات سیستم چیدمان Compose و مختصات 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)
        )
    }
}

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