تقدّم هذه الصفحة نظرة عامة عالية المستوى على الطبقات المعمارية التي يتكوّن منها Jetpack Compose، والمبادئ الأساسية التي يستند إليها هذا التصميم.
إنّ Jetpack Compose ليس مشروعًا واحدًا متكاملاً، بل تم إنشاؤه من عدد من الوحدات التي يتم تجميعها معًا لتشكيل حزمة كاملة. إنّ فهم الوحدات المختلفة التي يتألف منها Jetpack Compose يتيح لك ما يلي:
- استخدام مستوى التجريد المناسب لإنشاء تطبيقك أو مكتبتك
- التعرّف على الحالات التي يمكنك فيها الانتقال إلى مستوى أدنى للحصول على المزيد من التحكّم أو التخصيص
- تقليل التبعيات
الطبقات
الطبقات الرئيسية في Jetpack Compose هي:
الشكل 1. الطبقات الرئيسية في Jetpack Compose
ويتم إنشاء كل طبقة استنادًا إلى المستويات الأدنى، مع دمج الوظائف لإنشاء مكونات ذات مستوى أعلى. تستند كل طبقة إلى واجهات برمجة التطبيقات العامة للطبقات الأدنى للتحقّق من حدود الوحدات وإتاحة إمكانية استبدال أي طبقة عند الحاجة. لنتعرّف على هذه الطبقات من الأسفل إلى الأعلى.
- وقت التشغيل
- توفّر هذه الوحدة أساسيات وقت تشغيل Compose، مثل
remember
وmutableStateOf
والشرح التوضيحي@Composable
وSideEffect
. يمكنك الاستفادة من هذه الطبقة مباشرةً إذا كنت بحاجة فقط إلى إمكانات إدارة بنية Compose، وليس واجهة المستخدم. - UI
- تتكوّن طبقة واجهة المستخدم من وحدات متعدّدة (
ui-text
وui-graphics
وui-tooling
وما إلى ذلك). تنفِّذ هذه الوحدات أساسيات أدوات واجهة المستخدم، مثلLayoutNode
،Modifier
، ومعالجات الإدخال، والتنسيقات المخصّصة، والرسم. يمكنك الاستفادة من هذه الطبقة إذا كنت بحاجة إلى المفاهيم الأساسية فقط لمجموعة أدوات واجهة المستخدم. - Foundation
- يوفّر هذا النموذج وحدات أساسية مستقلة عن نظام التصميم لواجهة مستخدم Compose،
مثل
Row
وColumn
وLazyColumn
والتعرّف على إيماءات معيّنة وما إلى ذلك. يمكنك الاستفادة من الطبقة الأساسية لإنشاء نظام التصميم الخاص بك. - المادة الأساسية
- توفّر هذه الوحدة تنفيذًا لنظام Material Design في واجهة مستخدم Compose، وتوفّر نظامًا لتطبيق السمات ومكوّنات منمّقة ومؤشرات تموّج وأيقونات. يمكنك الاستفادة من هذه الطبقة عند استخدام Material Design في تطبيقك.
مبادئ التصميم
من المبادئ التوجيهية في Jetpack Compose توفير أجزاء صغيرة ومركزة من الوظائف التي يمكن تجميعها (أو إنشاؤها) معًا، بدلاً من عدد قليل من المكوّنات المتكاملة. لهذا الأسلوب عدد من المزايا.
التحكّم
تميل المكوّنات ذات المستوى الأعلى إلى تقديم المزيد من الميزات، ولكنّها تحدّ من مقدار التحكّم المباشر المتاح لك. إذا كنت بحاجة إلى مزيد من التحكّم، يمكنك النقر على السهم المتّجه للأسفل لاستخدام مكوّن على مستوى أدنى.
على سبيل المثال، إذا أردت تحريك لون أحد المكوّنات، يمكنك استخدام واجهة برمجة التطبيقات
animateColorAsState
على النحو التالي:
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
استنادًا إلى واجهة برمجة التطبيقات ذات المستوى الأدنى Animatable
. إنّ استخدام واجهة برمجة التطبيقات ذات المستوى الأدنى أكثر تعقيدًا، ولكنّه يوفّر المزيد من التحكّم. اختَر مستوى التجريد الأنسب لاحتياجاتك.
التخصيص
يؤدي تجميع المكوّنات ذات المستوى الأعلى من وحدات البناء الأصغر إلى تسهيل عملية تخصيص المكوّنات بشكل كبير عند الحاجة إلى ذلك. على سبيل المثال، ضع في اعتبارك
عملية التنفيذ
Button
التي توفّرها طبقة Material:
@Composable fun Button( // … content: @Composable RowScope.() -> Unit ) { Surface(/* … */) { CompositionLocalProvider(/* … */) { // set LocalContentAlpha ProvideTextStyle(MaterialTheme.typography.button) { Row( // … content = content ) } } } }
يتم تجميع Button
من 4 مكوّنات:
مادة
Surface
توفّر الخلفية والشكل والتعامل مع النقرات وما إلى ذلكA
CompositionLocalProvider
الذي يغيّر قيمة ألفا للمحتوى عند تفعيل الزر أو إيقافهيضبط A
ProvideTextStyle
نمط النص التلقائي الذي سيتم استخدامهيوفر
Row
سياسة التنسيق التلقائية لمحتوى الزر
لقد حذفنا بعض المَعلمات والتعليقات لتوضيح البنية، ولكن يبلغ عدد أسطر الرمز البرمجي للمكوّن بأكمله 40 سطرًا تقريبًا لأنّه يجمع هذه المكوّنات الأربعة لتنفيذ الزر. تتضمّن المكوّنات، مثل Button
، خيارات محدّدة بشأن المَعلمات التي تعرضها، مع تحقيق التوازن بين إتاحة التخصيصات الشائعة وتجنُّب كثرة المَعلمات التي قد تجعل المكوّن أكثر صعوبة في الاستخدام. على سبيل المثال، توفّر مكوّنات Material عمليات تخصيص محدّدة في نظام Material Design، ما يسهّل اتّباع مبادئ تصميم Material.
ومع ذلك، إذا كنت تريد إجراء تخصيص يتجاوز مَعلمات أحد المكوّنات، يمكنك "النزول" إلى مستوى أدنى وتفريغ مكوّن. على سبيل المثال، يحدّد Material
Design أنّه يجب أن تكون خلفية الأزرار بلون خالص. إذا كنت بحاجة إلى خلفية متدرّجة الألوان، لا يتيح لك هذا الخيار استخدام المَعلمات 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 للحصول على مثال حول إنشاء نظام تصميم مخصّص.
أفلام مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون JavaScript غير مفعّلة
- Kotlin لـ Jetpack Compose
- القوائم والشبكات
- الآثار الجانبية في Compose