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

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

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

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

لایه‌ها

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

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

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

زمان اجرا
این ماژول اصول اولیه زمان اجرای Compose مانند remember ، mutableStateOf ، حاشیه‌نویسی @Composable و SideEffect را ارائه می‌دهد. اگر فقط به قابلیت‌های مدیریت درخت Compose نیاز دارید، نه رابط کاربری آن، می‌توانید ساخت مستقیم بر روی این لایه را در نظر بگیرید.
رابط کاربری
لایه رابط کاربری از چندین ماژول ( ui-text ، ui-graphics ، ui-tooling و غیره) تشکیل شده است. این ماژول‌ها اصول اولیه جعبه ابزار رابط کاربری، مانند LayoutNode ، Modifier ، input handlers، layouts custom و drawing را پیاده‌سازی می‌کنند. اگر فقط به مفاهیم اساسی جعبه ابزار رابط کاربری نیاز دارید، می‌توانید ساخت بر اساس این لایه را در نظر بگیرید.
بنیاد
این ماژول بلوک‌های سازنده مستقل از سیستم طراحی را برای رابط کاربری Compose فراهم می‌کند، مانند Row and Column ، LazyColumn ، تشخیص حرکات خاص و غیره. می‌توانید برای ایجاد سیستم طراحی خودتان، ساخت بر اساس لایه پایه را در نظر بگیرید.
مواد
این ماژول پیاده‌سازی سیستم طراحی متریال را برای رابط کاربری Compose ارائه می‌دهد و یک سیستم قالب‌بندی، کامپوننت‌های استایل‌بندی‌شده، نشانه‌های موج‌دار و آیکون‌ها را فراهم می‌کند. هنگام استفاده از طراحی متریال در برنامه خود، بر اساس این لایه عمل کنید.

اصول طراحی

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

کنترل

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

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

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

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

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

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

سفارشی‌سازی

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

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

یک Button از 4 جزء مونتاژ می‌شود:

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

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

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

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

ما برخی از پارامترها و نظرات را حذف کرده‌ایم تا ساختار واضح‌تر شود، اما کل کامپوننت فقط حدود ۴۰ خط کد است زیرا به سادگی این ۴ کامپوننت را برای پیاده‌سازی دکمه مونتاژ می‌کند. کامپوننت‌هایی مانند Button در مورد اینکه کدام پارامترها را نمایش می‌دهند، نظر خود را دارند و بین امکان سفارشی‌سازی‌های رایج در برابر انفجار پارامترها که می‌تواند استفاده از یک کامپوننت را دشوارتر کند، تعادل برقرار می‌کنند. به عنوان مثال، کامپوننت‌های Material سفارشی‌سازی‌های مشخص شده در سیستم Material Design را ارائه می‌دهند و پیروی از اصول طراحی 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 جایگزین می‌کند و آن را سبک‌بندی می‌کند تا به ظاهر دلخواه برسد.

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

@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 مراجعه کنید.

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