مبانی چیدمان Compose

‫Jetpack Compose طراحی و ساخت میانای کاربر برنامه را بسیار آسان‌تر می‌کند. Compose وضعیت را ازطریق موارد زیر به عناصر میانای کاربر تبدیل می‌کند:

  1. ترکیب عناصر
  2. چیدمان عناصر
  3. طراحی عناصر

Compose transforming state to UI via composition, layout, drawing

این سند بر چیدمان عناصر تمرکز دارد و برخی‌از واحدهای سازنده‌ای را که Compose برای کمک به چیدمان عناصر میانای کاربر ارائه می‌دهد توضیح می‌دهد.

اهداف چیدمان‌ها در Compose

پیاده‌سازی Jetpack Compose از سیستم طرح‌بندی دو هدف اصلی دارد:

مبانی توابع ترکیب‌پذیر

توابع ترکیب‌پذیر واحد سازنده پایه Compose هستند. تابع ترکیب‌پذیر تابعی است که Unit را منتشر می‌کند و بخشی از واسط کاربر شما را توصیف می‌کند. تابع ورودی را دریافت می‌کند و آنچه را روی صفحه نشان داده می‌شود تولید می‌کند. برای اطلاعات بیشتر درباره composable، به مستندات مدل ذهنی Compose نگاهی بیندازید.

یک تابع ترکیب‌پذیر ممکن است چندین عنصر میانای کاربر را منتشر کند. اما اگر راهنمایی نکنید که چگونه باید چیده شوند، Compose ممکن است عناصر را به‌گونه‌ای بچیند که دوست نداشته باشید. برای مثال، این کد دو عنصر نوشتاری تولید می‌کند:

@Composable
fun ArtistCard() {
    Text("Alfred Sisley")
    Text("3 minutes ago")
}

بدون راهنمایی درباره نحوه چیدمان آن‌ها، Compose عناصر نوشتاری را روی هم قرار می‌دهد و آن‌ها را ناخوانا می‌کند:

دو عنصر نوشتاری روی یکدیگر کشیده شده‌اند و نوشتار را ناخوانا کرده‌اند

‫Compose مجموعه‌ای از چیدمان‌های آماده برای استفاده را ارائه می‌دهد تا به شما در چیدمان عناصر میانای کاربر کمک کند و تعریف چیدمان‌های تخصصی‌تر را برای شما آسان می‌کند.

اجزای چیدمان استاندارد

در بسیاری از موارد، می‌توانید فقط از عناصر چیدمان استاندارد Compose استفاده کنید.

از Column برای قرار دادن عمودی موارد در صفحه استفاده کنید.

@Composable
fun ArtistCardColumn() {
    Column {
        Text("Alfred Sisley")
        Text("3 minutes ago")
    }
}

دو عنصر نوشتاری که در چیدمان ستونی مرتب شده‌اند تا نوشتار خوانا باشد

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

@Composable
fun ArtistCardRow(artist: Artist) {
    Row(verticalAlignment = Alignment.CenterVertically) {
        Image(bitmap = artist.image, contentDescription = "Artist image")
        Column {
            Text(artist.name)
            Text(artist.lastSeenOnline)
        }
    }
}

چیدمان پیچیده‌تری را نشان می‌دهد، با یک گرافیک کوچک در کنار ستونی از عناصر نوشتاری

از Box برای قرار دادن عناصر روی یکدیگر استفاده کنید. ‫Box همچنین از پیکربندی تراز خاص عناصر موجود در آن پشتیبانی می‌کند.

@Composable
fun ArtistAvatar(artist: Artist) {
    Box {
        Image(bitmap = artist.image, contentDescription = "Artist image")
        Icon(Icons.Filled.Check, contentDescription = "Check mark")
    }
}

دو عنصر را که روی هم قرار گرفته‌اند نشان می‌دهد

اغلب این واحدهای سازنده تمام چیزی است که نیاز دارید. می‌توانید تابع ترکیب‌پذیر خودتان را بنویسید تا این چیدمان‌ها را در چیدمان پیچیده‌تری که مناسب برنامه‌تان است ترکیب کنید.

سه عنصر ترکیبی چیدمان ساده را مقایسه می‌کند: ستون، ردیف، و چارگوش

برای تنظیم موقعیت فرزندان در Row، آرگومان‌های horizontalArrangement و verticalAlignment را تنظیم کنید. برای Column، آرگومان‌های verticalArrangement و horizontalAlignment را تنظیم کنید:

@Composable
fun ArtistCardArrangement(artist: Artist) {
    Row(
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.End
    ) {
        Image(bitmap = artist.image, contentDescription = "Artist image")
        Column { /*...*/ }
    }
}

موارد در سمت راست تراز شده‌اند

مدل چیدمان

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

به‌طور خلاصه، والدین قبل‌از فرزندانشان اندازه‌گیری می‌شوند، اما بعداز فرزندانشان اندازه‌گذاری و جای‌گذاری می‌شوند.

تابع SearchResult زیر را درنظر بگیرید.

@Composable
fun SearchResult() {
    Row {
        Image(
            // ...
        )
        Column {
            Text(
                // ...
            )
            Text(
                // ...
            )
        }
    }
}

این تابع درخت واسط کاربر زیر را تولید می‌کند.

SearchResult
  Row
    Image
    Column
      Text
      Text

در مثال SearchResult، چیدمان درخت UI از این ترتیب پیروی می‌کند:

  1. از گره ریشه Row خواسته می‌شود اندازه‌گیری کند.
  2. گره ریشه Row از اولین فرزندش، Image، می‌خواهد اندازه‌گیری کند.
  3. Image یک گره برگ است (یعنی فرزند ندارد)، بنابراین اندازه را گزارش می‌کند و دستورالعمل‌های جای آگهی را برمی‌گرداند.
  4. گره ریشه Row از فرزند دوم خود، Column، می‌خواهد اندازه‌گیری کند.
  5. گره Column از اولین فرزند Text خود می‌خواهد اندازه‌گیری کند.
  6. اولین گره Text یک گره برگ است، بنابراین اندازه را گزارش می‌دهد و دستورالعمل‌های جای‌گذاری را برمی‌گرداند.
  7. گره Column از فرزند دوم Text خود می‌خواهد اندازه‌گیری کند.
  8. گره Text دوم یک گره برگ است، بنابراین اندازه را گزارش می‌کند و دستورالعمل‌های جای‌گذاری را برمی‌گرداند.
  9. اکنون که گره Column فرزندان خود را اندازه‌گیری، سایزبندی، و جای‌گذاری کرده است، می‌تواند اندازه و جای‌گذاری خود را تعیین کند.
  10. اکنون که گره ریشه Row فرزندانش را اندازه‌گیری، سایزبندی، و جای‌گذاری کرده است، می‌تواند اندازه و جای‌گذاری خودش را تعیین کند.

ترتیب اندازه‌گیری، تعیین اندازه، و جای‌گذاری در درخت میانای کاربری «نتایج جستجو»

عملکرد

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

اگر چیدمان شما به دلایلی به چندین اندازه‌گیری نیاز دارد، Compose سیستم ویژه‌ای را ارائه می‌دهد: اندازه‌گیری‌های ذاتی. می‌توانید درباره این ویژگی در اندازه‌گیری‌های ذاتی در چیدمان‌های Compose بیشتر بخوانید.

ازآنجایی‌که اندازه‌گیری و جای‌گذاری زیرفازهای متمایزی از مرحله چیدمان هستند، هر تغییری که فقط بر جای‌گذاری موارد تأثیر بگذارد و نه بر اندازه‌گیری، می‌تواند به‌طور جداگانه اجرا شود.

استفاده از اصلاح‌گرها در چیدمان‌ها

همان‌طور که در اصلاح‌کننده‌های Compose بحث شد، می‌توانید از اصلاح‌کننده‌ها برای تزئین یا تقویت composable-هایتان استفاده کنید. اصلاح‌کننده‌ها برای سفارشی‌سازی چیدمان شما ضروری هستند. برای مثال، در اینجا چند اصلاح‌کننده را زنجیره‌ای می‌کنیم تا ArtistCard را سفارشی‌سازی کنیم:

@Composable
fun ArtistCardModifiers(
    artist: Artist,
    onClick: () -> Unit
) {
    val padding = 16.dp
    Column(
        Modifier
            .clickable(onClick = onClick)
            .padding(padding)
            .fillMaxWidth()
    ) {
        Row(verticalAlignment = Alignment.CenterVertically) { /*...*/ }
        Spacer(Modifier.size(padding))
        Card(
            elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
        ) { /*...*/ }
    }
}

چیدمانی پیچیده‌تر که از اصلاح‌کننده‌ها برای تغییر نحوه چیدمان گرافیک‌ها و اینکه کدام نواحی به ورودی کاربر پاسخ می‌دهند استفاده می‌کند

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

  • clickable باعث می‌شود که یک composable به ورودی کاربر واکنش نشان دهد و موجی را نمایش دهد.
  • padding فضایی را در اطراف عنصر قرار می‌دهد.
  • fillMaxWidth باعث می‌شود که composable حداکثر عرضی را که از والد خود دریافت کرده است پر کند.
  • size() عرض و ارتفاع ترجیحی عنصر را مشخص می‌کند.

چیدمان‌های قابل‌پیمایش

در اسناد اشاره‌های Compose درباره چیدمان‌های پیمایشی بیشتر بدانید.

برای فهرست‌ها و فهرست‌های تنبل، اسناد Compose lists را بررسی کنید.

چیدمان‌های واکنش‌گرا

طرح‌بندی باید با درنظر گرفتن جهت‌های مختلف صفحه‌نمایش و اندازه‌های ضریب شکل طراحی شود. Compose چند سازوکار آماده برای تسهیل تطبیق چیدمان‌های ترکیب‌پذیر با پیکربندی‌های مختلف صفحه ارائه می‌دهد.

محدودیت‌ها

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

@Composable
fun WithConstraintsComposable() {
    BoxWithConstraints {
        Text("My minHeight is $minHeight while my maxWidth is $maxWidth")
    }
}

چیدمان‌های مبتنی بر جایگاه

Compose انواع مختلفی از composable را براساس طراحی مواد با وابستگی androidx.compose.material:material (که هنگام ایجاد پروژه Compose در Android Studio گنجانده شده است) ارائه می‌دهد تا ساخت واسط کاربر را آسان کند. عناصری مثل Drawer، FloatingActionButton، و TopAppBar همگی ارائه شده‌اند.

مؤلفه‌های Material به‌شدت از میاناهای برنامه‌سازی کاربردی شکاف استفاده می‌کنند، الگویی که Compose معرفی می‌کند تا لایه‌ای از سفارشی‌سازی را به بالای composableها اضافه کند. این رویکرد مؤلفه‌ها را انعطاف‌پذیرتر می‌کند، زیرا آن‌ها عنصر فرزندی را می‌پذیرند که می‌تواند خودش را پیکربندی کند، به‌جای اینکه مجبور باشد هر پارامتر پیکربندی فرزند را افشا کند. جایگاه‌ها فضای خالی‌ای در واسط کاربر باقی می‌گذارند تا توسعه‌دهنده بتواند آن را به‌دلخواه خود پر کند. برای مثال، این‌ها جایگاه‌هایی هستند که می‌توانید در TopAppBar سفارشی‌سازی کنید:

نموداری که جایگاه‌های دردسترس را در نوار برنامه «مؤلفه‌های Material» نشان می‌دهد

Composables usually take a content composable lambda ( content: @Composable () -> Unit). Slot APIs expose multiple content parameters for specific uses. برای مثال، TopAppBar به شما امکان می‌دهد محتوای title، navigationIcon، و actions را ارائه دهید.

برای مثال، Scaffold به شما امکان می‌دهد میانای کاربری را با ساختار چیدمان Material Design پایه پیاده‌سازی کنید. Scaffoldجایگاه‌هایی برای رایج‌ترین مؤلفه‌های Material سطح بالا ارائه می‌دهد، مانند TopAppBar، BottomAppBar، FloatingActionButton، و Drawer. بااستفاده از Scaffold، به‌راحتی می‌توان مطمئن شد که این مؤلفه‌ها به‌درستی قرار گرفته‌اند و به‌درستی باهم کار می‌کنند.

برنامه نمونه JetNews که از Scaffold برای جای‌گذاری چند عنصر استفاده می‌کند

@Composable
fun HomeScreen(/*...*/) {
    ModalNavigationDrawer(drawerContent = { /* ... */ }) {
        Scaffold(
            topBar = { /*...*/ }
        ) { contentPadding ->
            // ...
        }
    }
}