لایه‌بندی معماری Jetpack Compose

این صفحه نمای کلی سطح بالایی از لایه‌های معماری تشکیل‌دهنده Jetpack Compose و اصول اصلی‌ای که این طراحی را شکل می‌دهند ارائه می‌دهد.

‫Jetpack Compose یک پروژه یکپارچه واحد نیست؛ این پروژه از تعدادی واحد تشکیل شده است که با هم ترکیب می‌شوند تا یک پشته کامل را تشکیل دهند. آشنایی با پیمانه‌های مختلفی که Jetpack Compose را تشکیل می‌دهند به شما امکان می‌دهد:

  • برای ساختن برنامه یا کتابخانه، از سطح مناسبی از انتزاع استفاده کنید
  • درک اینکه چه زمانی می‌توانید برای کنترل یا سفارشی‌سازی بیشتر به سطح پایین‌تری «نزول کنید»
  • وابستگی‌هایتان را به حداقل برسانید

لایه‌ها

لایه‌های اصلی Jetpack Compose عبارت‌اند از:

شکل ۱. لایه‌های اصلی Jetpack Compose.

هر لایه بر روی سطوح پایین‌تر ساخته می‌شود و با ترکیب عملکرد، اجزای سطح بالاتر را ایجاد می‌کند. هر لایه براساس «میاناهای برنامه‌سازی کاربردی» عمومی لایه‌های پایین‌تر ساخته می‌شود تا مرزهای واحد را به‌تأیید برساند و به شما امکان دهد درصورت نیاز هر لایه‌ای را جایگزین کنید. بیایید این لایه‌ها را از پایین به بالا بررسی کنیم.

زمان اجرا
این واحد اصول اولیه زمان اجرای Compose را ارائه می‌دهد، مثل remember، mutableStateOf، حاشیه‌نویسی @Composable و SideEffect. اگر فقط به قابلیت‌های مدیریت درخت Compose نیاز دارید، نه واسط کاربری آن، شاید بهتر باشد مستقیماً روی این لایه بسازید.
UI
لایه میانای کاربر از چندین واحد تشکیل شده است ( ui-text، ui-graphics، ui-tooling، و غیره). این واحدها اصول اولیه جعبه‌ابزار میانای کاربر را پیاده‌سازی می‌کنند، مثل LayoutNode، Modifier، مدیریت‌کننده‌های ورودی، چیدمان‌های سفارشی، و طراحی. اگر فقط به مفاهیم بنیادی ابزارک‌های میانای کاربر نیاز دارید، می‌توانید از این لایه استفاده کنید.
Foundation
این واحد بلوک‌های ساختمانی مستقل از سیستم طراحی برای «میانای کاربری Compose» ارائه می‌دهد، مانند Row و Column، LazyColumn، تشخیص اشاره‌های خاص، و غیره. می‌توانید با ساختن روی لایه پایه، سیستم طراحی خودتان را ایجاد کنید.
مطالب
این واحد پیاده‌سازی سیستم «طراحی مواد» را برای واسط کاربر Compose ارائه می‌دهد و سیستم زمینه‌سازی، عناصر سبک‌دار، نشان‌های موج‌دار، و نمادها را فراهم می‌کند. هنگام استفاده از «طراحی مواد» در برنامه، روی این لایه بسازید.

اصول طراحی

یکی از اصول راهنمای Jetpack Compose ارائه قطعات کوچک و متمرکز از عملکرد است که می‌توانند با هم مونتاژ (یا ترکیب) شوند، به‌جای چند عنصر یکپارچه. این رویکرد مزایای متعددی دارد.

کنترل

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

برای مثال، اگر می‌خواهید رنگ یک عنصر را پویانمایی کنید، می‌توانید از animateColorAsState API استفاده کنید:

val color = animateColorAsState(if (condition) Color.Green else Color.Red)

بااین‌حال، اگر نیاز دارید که عنصر همیشه خاکستری شروع شود، نمی‌توانید این کار را با این API انجام دهید. درعوض، می‌توانید از سطح پایین‌تر Animatable میانای برنامه‌سازی کاربردی استفاده کنید:

val color = remember { Animatable(Color.Gray) }
LaunchedEffect(condition) {
    color.animateTo(if (condition) Color.Green else Color.Red)
}

خود «میانای برنامه‌سازی کاربردی» سطح بالاتر animateColorAsState برپایه «میانای برنامه‌سازی کاربردی» سطح پایین‌تر Animatable ساخته شده است. استفاده از API سطح پایین‌تر پیچیده‌تر است اما کنترل بیشتری ارائه می‌دهد. سطح انتزاعی را انتخاب کنید که بهترین تناسب را با نیازهایتان داشته باشد.

سفارشی‌سازی

سرهم کردن عناصر سطح بالاتر از واحدهای سازنده کوچک‌تر، سفارشی‌سازی عناصر را درصورت نیاز بسیار آسان‌تر می‌کند. برای مثال، پیاده‌سازی Button ارائه‌شده توسط لایه Material را درنظر بگیرید:

@Composable
fun Button(
    // …
    content: @Composable RowScope.() -> Unit
) {
    Surface(/* … */) {
        CompositionLocalProvider(/* … */) { // set LocalContentAlpha
            ProvideTextStyle(MaterialTheme.typography.button) {
                Row(
                    // …
                    content = content
                )
            }
        }
    }
}

یک Button از ۴ عنصر تشکیل شده است:

  1. ماده‌ای Surface که پس‌زمینه، شکل، مدیریت کلیک، و غیره را ارائه می‌دهد.

  2. A CompositionLocalProvider که وقتی دکمه فعال یا غیرفعال می‌شود، آلفای محتوا را تغییر می‌دهد

  3. A ProvideTextStyle سبک نوشتار پیش‌فرض را برای استفاده تنظیم می‌کند

  4. Row خط‌مشی چیدمان پیش‌فرض را برای محتوای دکمه ارائه می‌دهد

برخی‌از پارامترها و نظرات را حذف کرده‌ایم تا ساختار واضح‌تر شود، اما کل عنصر فقط حدود ۴۰ خط کد دارد زیرا به‌سادگی این ۴ عنصر را برای پیاده‌سازی دکمه مونتاژ می‌کند. عناصری مثل Button درباره اینکه کدام پارامترها را نمایان کنند نظر دارند و بین فعال کردن سفارشی‌سازی‌های رایج و نمایان کردن تعداد زیادی پارامتر که می‌تواند استفاده از عنصر را سخت‌تر کند تعادل برقرار می‌کنند. مؤلفه‌های «طراحی سه‌بعدی»، برای مثال، سفارشی‌سازی‌هایی را که در سیستم «طراحی سه‌بعدی» مشخص شده است ارائه می‌دهند و پیروی از اصول «طراحی سه‌بعدی» را آسان می‌کنند.

بااین‌حال، اگر می‌خواهید سفارشی‌سازی فراتر از پارامترهای یک عنصر انجام دهید، می‌توانید یک سطح «پایین بیاورید» و یک عنصر را انشعاب دهید. برای مثال، «طراحی Material» مشخص می‌کند که دکمه‌ها باید پس‌زمینه‌ای با رنگ یکدست داشته باشند. اگر به پس‌زمینه گرادیانی نیاز دارید، این گزینه توسط پارامترهای Button پشتیبانی نمی‌شود. در این مورد می‌توانید از پیاده‌سازی Button «طراحی مواد» به‌عنوان مرجع استفاده کنید و مؤلفه خودتان را بسازید:

@Composable
fun GradientButton(
    // …
    background: List<Color>,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Row(
        // …
        modifier = modifier
            .clickable(onClick = {})
            .background(
                Brush.horizontalGradient(background)
            )
    ) {
        CompositionLocalProvider(/* … */) { // set material LocalContentAlpha
            ProvideTextStyle(MaterialTheme.typography.button) {
                content()
            }
        }
    }
}

پیاده‌سازی بالا همچنان از عناصر لایه Material استفاده می‌کند، مثل مفاهیم Material درباره آلفای محتوای فعلی و سبک نوشتاری فعلی. بااین‌حال، این ویژگی ماده Surface را با Row جایگزین می‌کند و آن را به‌سبک موردنظر درمی‌آورد تا ظاهر دلخواه را به‌دست آورد.

اگر اصلاً نمی‌خواهید از مفاهیم Material استفاده کنید، برای مثال اگر می‌خواهید سیستم طراحی سفارشی خودتان را بسازید، می‌توانید به استفاده صرف از عناصر لایه پایه بروید:

@Composable
fun BespokeButton(
    // …
    backgroundColor: Color,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Row(
        // …
        modifier = modifier
            .clickable(onClick = {})
            .background(backgroundColor)
    ) {
        // No Material components used
        content()
    }
}

‫Jetpack Compose ساده‌ترین نام‌ها را برای بالاترین سطح عناصر رزرو می‌کند. برای مثال، androidx.compose.material.Text برپایه androidx.compose.foundation.text.BasicText ساخته شده است. این امکان را فراهم می‌کند که اگر می‌خواهید سطوح بالاتر را جایگزین کنید، پیاده‌سازی خودتان را با نامی که بیشترین قابلیت کشف را دارد ارائه دهید.

انتخاب انتزاع مناسب

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

برای مثال، اگر می‌خواهید پشتیبانی از اشاره را به عنصر سفارشی‌تان اضافه کنید، می‌توانید آن را از صفر بااستفاده از Modifier.pointerInput بسازید اما عناصر سطح بالاتری که روی این عنصر ساخته شده‌اند وجود دارند که ممکن است نقطه شروع بهتری ارائه دهند، برای مثال Modifier.draggable، Modifier.scrollable یا Modifier.swipeable.

به‌طورکلی، ترجیح دهید روی عنصر سطح بالا بسازید که عملکرد موردنیاز شما را ارائه می‌دهد تا از روش‌های مطلوب موجود در آن بهره‌مند شوید.

بیشتر بدانید

برای نمونه‌ای از ساختن سیستم طراحی سفارشی، نمونه Jetsnack را ببینید.