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

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

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

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

لایه‌ها

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

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

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

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

اصول طراحی

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

کنترل

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

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

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

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

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

‫animateColorAsState API سطح بالاتر خودش براساس Animatable API سطح پایین‌تر ساخته شده است. استفاده از 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 سفارشی‌سازی‌های مشخص‌شده در سیستم Material Design را ارائه می‌دهند و پیروی از اصول طراحی Material را آسان می‌کنند.

اما اگر می‌خواهید سفارشی‌سازی را فراتر از پارامترهای مؤلفه انجام دهید، می‌توانید یک سطح «پایین بروید» و مؤلفه را منشعب کنید. برای مثال، «طراحی مواد» مشخص می‌کند که دکمه‌ها باید پس‌زمینه رنگی یک‌دست داشته باشند. اگر به پس‌زمینه گرادیان نیاز دارید، این گزینه توسط پارامترهای Button پشتیبانی نمی‌شود. در این حالت می‌توانید از پیاده‌سازی Material 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 را ببینید.