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

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

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

ترکیب کردن وضعیت تبدیل به میانای کاربر ازطریق ترکیب، چیدمان، رسم

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

اهداف چیدمان‌ها در «نوشتن»

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

اصول اولیه توابع ساختنی

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

یک تابع ترکیب‌شدنی ممکن است چندین عنصر واسط کاربر را منتشر کند. بااین‌حال، اگر راهنمایی درباره نحوه چیدمان آن‌ها ارائه ندهید، «نگارش» ممکن است عناصر را به روشی که شما دوست ندارید بچیند. برای مثال، این کد دو عنصر نوشتاری تولید می‌کند:

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

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

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

‫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، چیدمان درخت واسط کاربر از این ترتیب پیروی می‌کند:

  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 اجازه می‌دهد درخت‌های UI عمیق را به‌طور کارآمد مدیریت کند. برای مثال، اگر عنصری فرزندش را دوبار اندازه‌گیری کند و آن فرزند هریک از فرزندانش را دوبار اندازه‌گیری کند و غیره، یک تلاش برای چیدن کل رابط کاربری باید کار زیادی انجام دهد و این امر حفظ عملکرد خوب برنامه را دشوار می‌کند.

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

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

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

همان‌طور که در اصلاح‌کننده‌های Compose بحث شد، می‌توانید از اصلاح‌کننده‌ها برای تزئین یا تقویت عناصر ترکیبی استفاده کنید. «اصلاح‌کننده‌ها» برای سفارشی‌سازی چیدمان شما ضروری هستند. برای مثال، در اینجا چند اصلاح‌کننده را به‌هم زنجیر می‌کنیم تا 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 باعث می‌شود عنصر ترکیبی به ورودی کاربر واکنش نشان دهد و موجی نشان دهد.
  • ‫padding در اطراف عنصر فاصله ایجاد می‌کند.
  • ‫fillMaxWidth باعث می‌شود عنصر ترکیبی حداکثر پهنای داده‌شده از عنصر والد خود را پر کند.
  • ‫size() عرض و ارتفاع ترجیحی عنصر را مشخص می‌کند.

چیدمان‌های پیمایش‌پذیر

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

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

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

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

محدودیت‌ها

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

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

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

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

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

نموداری که جایگاه‌های دردسترس را در نوار برنامه «عناصر مادی» نشان می‌دهد

ترکیب‌پذیرها معمولاً یک لامبدای ترکیب‌پذیر content ( content: @Composable () -> Unit) می‌گیرند. میاناهای برنامه‌سازی کاربردی شکاف چندین پارامتر content را برای استفاده‌های خاص آشکار می‌کنند. برای مثال، TopAppBar به شما امکان می‌دهد محتوای title، navigationIcon، و actions را ارائه دهید.

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

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

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