طرح بندی های سفارشی

در Compose، عناصر رابط کاربری توسط توابع composable نمایش داده می‌شوند که هنگام فراخوانی، بخشی از رابط کاربری را منتشر می‌کنند و سپس به درخت رابط کاربری اضافه می‌شوند که روی صفحه نمایش داده می‌شود. هر عنصر رابط کاربری دارای یک والد و احتمالاً چندین فرزند است. هر عنصر همچنین در داخل والد خود قرار دارد که به صورت موقعیت (x, y) و اندازه‌ای که به صورت width و height مشخص می‌شود، مشخص می‌شود.

والدین محدودیت‌هایی را برای عناصر فرزند خود تعریف می‌کنند. از یک عنصر خواسته می‌شود اندازه خود را در چارچوب آن محدودیت‌ها تعریف کند. محدودیت‌ها حداقل و حداکثر width و height یک عنصر را محدود می‌کنند. اگر یک عنصر دارای عناصر فرزند باشد، ممکن است هر فرزند را برای تعیین اندازه آن اندازه‌گیری کند. هنگامی که یک عنصر اندازه خود را تعیین و گزارش می‌کند، این فرصت را دارد که نحوه قرار دادن عناصر فرزند خود را نسبت به خودش تعریف کند، همانطور که در بخش ایجاد طرح‌بندی‌های سفارشی به تفصیل توضیح داده شده است.

چیدمان هر گره در درخت رابط کاربری یک فرآیند سه مرحله‌ای است. هر گره باید:

  1. هر کودکی را اندازه بگیرید
  2. اندازه خودش را تعیین کند
  3. فرزندانش را قرار دهید
سه مرحله از طرح‌بندی گره: اندازه‌گیری گره‌های فرزند، تعیین اندازه، قرار دادن گره‌های فرزند
شکل ۱. سه مرحله‌ی چیدمان گره‌ها عبارتند از اندازه‌گیری گره‌های فرزند، تعیین اندازه و قرار دادن گره‌های فرزند.

استفاده از دامنه‌ها مشخص می‌کند که چه زمانی می‌توانید فرزندان خود را اندازه‌گیری و قرار دهید. اندازه‌گیری یک طرح‌بندی فقط در طول مراحل اندازه‌گیری و طرح‌بندی قابل انجام است و یک فرزند فقط می‌تواند در طول مراحل طرح‌بندی (و فقط پس از اندازه‌گیری) قرار گیرد. به دلیل دامنه‌های Compose مانند MeasureScope و PlacementScope ، این امر در زمان کامپایل اعمال می‌شود.

از اصلاح‌کننده‌ی طرح‌بندی استفاده کنید

شما می‌توانید از اصلاح‌کننده‌ی طرح‌بندی ( layout modifier) ​​برای تغییر نحوه‌ی اندازه‌گیری و چیدمان یک عنصر استفاده کنید. Layout یک لامبدا است؛ پارامترهای آن شامل عنصری است که می‌توانید اندازه‌گیری کنید، که به عنوان measurable ارسال می‌شود، و محدودیت‌های ورودی آن composable که به عنوان constraints ارسال می‌شوند. یک اصلاح‌کننده‌ی طرح‌بندی سفارشی می‌تواند به این شکل باشد:

fun Modifier.customLayoutModifier() =
    layout { measurable, constraints ->
        // ...
    }

یک Text روی صفحه نمایش دهید و فاصله از بالا تا خط پایه اولین خط متن را کنترل کنید. این دقیقاً همان کاری است که اصلاح‌کننده paddingFromBaseline انجام می‌دهد؛ شما در اینجا آن را به عنوان مثال پیاده‌سازی می‌کنید. برای انجام این کار، از اصلاح‌کننده layout برای قرار دادن دستی composable روی صفحه استفاده کنید. در اینجا رفتار حاصل شده در حالتی که padding بالای Text روی 24.dp تنظیم شده باشد، آمده است:

تفاوت بین فاصله‌گذاری معمولی رابط کاربری که فاصله بین عناصر را تنظیم می‌کند و فاصله‌گذاری متنی که فاصله را از یک خط پایه تا خط پایه بعدی تنظیم می‌کند را نشان می‌دهد.
شکل ۲. متن با paddingFromBaseline اعمال شده.

کدی که این فاصله را ایجاد می‌کند، به این صورت است:

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)
    }
}

در این کد چه اتفاقی می‌افتد؟

  1. در پارامتر لامبدا measurable ، شما Text نمایش داده شده توسط پارامتر قابل اندازه‌گیری را با فراخوانی measurable.measure(constraints) اندازه‌گیری می‌کنید.
  2. شما اندازه‌ی ترکیب‌پذیری را با فراخوانی متد layout(width, height) مشخص می‌کنید، که همچنین یک لامبدا برای قرار دادن عناصر پیچیده شده ارائه می‌دهد. در این حالت، این ارتفاع بین آخرین خط پایه و padding بالای اضافه شده است.
  3. شما عناصر پیچیده شده را با فراخوانی placeable.place(x, y) روی صفحه قرار می‌دهید. اگر عناصر پیچیده شده قرار داده نشوند، قابل مشاهده نخواهند بود. موقعیت y مربوط به padding بالایی است: موقعیت اولین خط پایه متن.

برای تأیید اینکه این کد طبق انتظار کار می‌کند، از این اصلاح‌کننده روی یک Text استفاده کنید:

@Preview
@Composable
fun TextWithPaddingToBaselinePreview() {
    MyApplicationTheme {
        Text("Hi there!", Modifier.firstBaselineToTop(32.dp))
    }
}

@Preview
@Composable
fun TextWithNormalPaddingPreview() {
    MyApplicationTheme {
        Text("Hi there!", Modifier.padding(top = 32.dp))
    }
}

پیش‌نمایش‌های چندگانه از عناصر متن؛ یکی فاصله‌گذاری معمولی بین عناصر را نشان می‌دهد، دیگری فاصله‌گذاری از یک خط پایه تا خط پایه بعدی را نشان می‌دهد.
شکل ۳. اصلاح‌کننده اعمال‌شده بر روی یک Text قابل ترکیب و پیش‌نمایش آن.

ایجاد طرح‌بندی‌های سفارشی

اصلاح‌کننده‌ی layout modifier) ​​فقط فراخوانی‌کننده‌ی composable را تغییر می‌دهد. برای اندازه‌گیری و چیدمان چندین composable، به جای آن از Layout composable استفاده کنید. این composable به شما امکان می‌دهد تا فرزندان را به صورت دستی اندازه‌گیری و چیدمان کنید. تمام طرح‌بندی‌های سطح بالاتر مانند Column و Row با Layout composable ساخته می‌شوند.

این مثال یک نسخه بسیار ابتدایی از Column را می‌سازد. اکثر طرح‌بندی‌های سفارشی از این الگو پیروی می‌کنند:

@Composable
fun MyBasicColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        // measure and position children given constraints logic here
        // ...
    }
}

مشابه با اصلاح‌کننده‌ی layout ، measurables فهرستی از فرزندانی است که باید اندازه‌گیری شوند و constraints محدودیت‌هایی از والد هستند. با پیروی از همان منطق قبلی، MyBasicColumn می‌تواند به صورت زیر پیاده‌سازی شود:

@Composable
fun MyBasicColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        // Don't constrain child views further, measure them with given constraints
        // List of measured children
        val placeables = measurables.map { measurable ->
            // Measure each children
            measurable.measure(constraints)
        }

        // Set the size of the layout as big as it can
        layout(constraints.maxWidth, constraints.maxHeight) {
            // Track the y co-ord we have placed children up to
            var yPosition = 0

            // Place children in the parent layout
            placeables.forEach { placeable ->
                // Position item on the screen
                placeable.placeRelative(x = 0, y = yPosition)

                // Record the y co-ord placed up to
                yPosition += placeable.height
            }
        }
    }
}

کامپوننت‌های فرزند توسط محدودیت‌های Layout (بدون محدودیت‌های minHeight ) محدود می‌شوند و بر اساس yPosition کامپوننت قبلی قرار می‌گیرند.

در اینجا نحوه استفاده از آن composable سفارشی آورده شده است:

@Composable
fun CallingComposable(modifier: Modifier = Modifier) {
    MyBasicColumn(modifier.padding(8.dp)) {
        Text("MyBasicColumn")
        Text("places items")
        Text("vertically.")
        Text("We've done it by hand!")
    }
}

چندین عنصر متنی که یکی بالای دیگری در یک ستون قرار گرفته‌اند.
شکل ۴. پیاده‌سازی Column سفارشی.

جهت چیدمان

جهت چیدمان یک composable را با تغییر ترکیب LocalLayoutDirection به صورت محلی تغییر دهید.

اگر به صورت دستی عناصر ترکیبی (composables) را روی صفحه قرار می‌دهید، LayoutDirection بخشی از LayoutScope مربوط به اصلاح‌کننده‌ی layout یا Layout composable است.

هنگام استفاده از layoutDirection ، کامپوننت‌ها را با استفاده از place قرار دهید. برخلاف متد placeRelative ، place بر اساس جهت چیدمان (چپ به راست در مقابل راست به چپ) تغییر نمی‌کند.

طرح‌بندی‌های سفارشی در عمل

برای کسب اطلاعات بیشتر در مورد طرح‌بندی‌ها و اصلاح‌کننده‌ها به بخش طرح‌بندی‌های پایه در Compose مراجعه کنید و طرح‌بندی‌های سفارشی را در عمل در نمونه‌های Compose که طرح‌بندی‌های سفارشی ایجاد می‌کنند، مشاهده کنید.

بیشتر بدانید

برای کسب اطلاعات بیشتر در مورد طرح‌بندی‌های سفارشی در Compose، به منابع اضافی زیر مراجعه کنید.

ویدیوها

{% کلمه به کلمه %} {% فعل کمکی %} {% کلمه به کلمه %} {% فعل کمکی %}