على الرغم من أنّ Material هو نظام التصميم الذي ننصح به، وأنّ Jetpack Compose يتضمّن عملية تنفيذ لنظام Material، إلا أنّه ليس عليك استخدامه. تم إنشاء Material بالكامل باستخدام واجهات برمجة تطبيقات عامة، لذا يمكنك إنشاء نظام التصميم الخاص بك بالطريقة نفسها.
يمكنك اتّباع عدة طرق:
- توسيع
MaterialTheme
باستخدام قيم إضافية خاصة بالمظهر - استبدال نظام واحد أو أكثر من أنظمة Material —
Colors
أوTypography
أوShapes
— بعمليات تنفيذ مخصّصة مع الحفاظ على الأنظمة الأخرى - تنفيذ نظام تصميم مخصّص بالكامل لاستبدال
MaterialTheme
قد تحتاج أيضًا إلى مواصلة استخدام مكونات Material مع نظام تصميم مخصّص. يمكنك إجراء ذلك، ولكن هناك بعض النقاط التي يجب مراعاتها لتناسب النهج الذي اتّبعته.
لمزيد من المعلومات حول البِنى وواجهات برمجة التطبيقات ذات المستوى الأدنى التي تستخدمها MaterialTheme
وأنظمة التصميم المخصّصة، يمكنك الاطّلاع على دليل بنية السمة في Compose.
توسيع نطاق Material Theme
تتّبع Compose Material عن كثب Material Theming لتسهيل اتّباع إرشادات Material وضمان سلامة الأنواع. ومع ذلك، يمكن توسيع مجموعات الألوان وأساليب الخطوط والأشكال باستخدام قيم إضافية.
أبسط طريقة هي إضافة خصائص الإضافة:
// Use with MaterialTheme.colorScheme.snackbarAction val ColorScheme.snackbarAction: Color @Composable get() = if (isSystemInDarkTheme()) Red300 else Red700 // Use with MaterialTheme.typography.textFieldInput val Typography.textFieldInput: TextStyle get() = TextStyle(/* ... */) // Use with MaterialTheme.shapes.card val Shapes.card: Shape get() = RoundedCornerShape(size = 20.dp)
ويوفّر ذلك اتساقًا مع واجهات برمجة التطبيقات الخاصة باستخدام MaterialTheme
. أحد الأمثلة على ذلك
الذي يحدّده Compose هو
surfaceColorAtElevation
،
الذي يحدّد لون السطح الذي يجب استخدامه حسب الارتفاع.
هناك طريقة أخرى وهي تحديد سمة موسّعة "تغلّف" MaterialTheme
وقيمها.
لنفترض أنّك تريد إضافة لونَين آخرَين، caution
وonCaution
، وهو لون أصفر يُستخدم للإجراءات التي تنطوي على بعض الخطورة، مع الاحتفاظ بألوان Material الحالية:
@Immutable data class ExtendedColors( val caution: Color, val onCaution: Color ) val LocalExtendedColors = staticCompositionLocalOf { ExtendedColors( caution = Color.Unspecified, onCaution = Color.Unspecified ) } @Composable fun ExtendedTheme( /* ... */ content: @Composable () -> Unit ) { val extendedColors = ExtendedColors( caution = Color(0xFFFFCC02), onCaution = Color(0xFF2C2D30) ) CompositionLocalProvider(LocalExtendedColors provides extendedColors) { MaterialTheme( /* colors = ..., typography = ..., shapes = ... */ content = content ) } } // Use with eg. ExtendedTheme.colors.caution object ExtendedTheme { val colors: ExtendedColors @Composable get() = LocalExtendedColors.current }
وهذا مشابه لواجهات برمجة التطبيقات الخاصة باستخدام MaterialTheme
. يتيح هذا العنصر أيضًا استخدام مواضيع متعددة،
إذ يمكنك تضمين عناصر ExtendedTheme
بالطريقة نفسها التي يتم بها تضمين عناصر MaterialTheme
.
استخدام مكوّنات Material
عند توسيع نطاق Material Theming، يتم الاحتفاظ بقيم MaterialTheme
الحالية، وستظل مكوّنات Material تتضمّن قيمًا تلقائية معقولة.
إذا كنت تريد استخدام قيم موسّعة في المكوّنات، يمكنك تضمينها في دوال قابلة للإنشاء خاصة بك، مع ضبط القيم التي تريد تغييرها مباشرةً، وعرض القيم الأخرى كمَعلمات في العنصر القابل للإنشاء الذي يحتوي على هذه القيم:
@Composable fun ExtendedButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( containerColor = ExtendedTheme.colors.caution, contentColor = ExtendedTheme.colors.onCaution /* Other colors use values from MaterialTheme */ ), onClick = onClick, modifier = modifier, content = content ) }
بعد ذلك، عليك استبدال استخدامات Button
بـ ExtendedButton
في المواضع المناسبة.
@Composable fun ExtendedApp() { ExtendedTheme { /*...*/ ExtendedButton(onClick = { /* ... */ }) { /* ... */ } } }
استبدال الأنظمة الفرعية في Material
بدلاً من توسيع نطاق Material Theming، يمكنك استبدال نظام واحد أو أكثر، مثل Colors
أو Typography
أو Shapes
، بتنفيذ مخصّص مع الحفاظ على الأنظمة الأخرى.
لنفترض أنّك تريد استبدال نظامَي النوع والشكل مع الاحتفاظ بنظام الألوان:
@Immutable data class ReplacementTypography( val body: TextStyle, val title: TextStyle ) @Immutable data class ReplacementShapes( val component: Shape, val surface: Shape ) val LocalReplacementTypography = staticCompositionLocalOf { ReplacementTypography( body = TextStyle.Default, title = TextStyle.Default ) } val LocalReplacementShapes = staticCompositionLocalOf { ReplacementShapes( component = RoundedCornerShape(ZeroCornerSize), surface = RoundedCornerShape(ZeroCornerSize) ) } @Composable fun ReplacementTheme( /* ... */ content: @Composable () -> Unit ) { val replacementTypography = ReplacementTypography( body = TextStyle(fontSize = 16.sp), title = TextStyle(fontSize = 32.sp) ) val replacementShapes = ReplacementShapes( component = RoundedCornerShape(percent = 50), surface = RoundedCornerShape(size = 40.dp) ) CompositionLocalProvider( LocalReplacementTypography provides replacementTypography, LocalReplacementShapes provides replacementShapes ) { MaterialTheme( /* colors = ... */ content = content ) } } // Use with eg. ReplacementTheme.typography.body object ReplacementTheme { val typography: ReplacementTypography @Composable get() = LocalReplacementTypography.current val shapes: ReplacementShapes @Composable get() = LocalReplacementShapes.current }
استخدام مكوّنات Material
عند استبدال نظام واحد أو أكثر من أنظمة MaterialTheme
، قد يؤدي استخدام مكوّنات Material كما هي إلى ظهور قيم غير مرغوب فيها للون المادة أو نوعها أو شكلها.
إذا كنت تريد استخدام قيم بديلة في المكوّنات، عليك تضمينها في دوال قابلة للإنشاء خاصة بك، مع ضبط القيم مباشرةً للنظام ذي الصلة، وعرض القيم الأخرى كمعلَمات للعنصر القابل للإنشاء الذي يحتوي على هذه القيم.
@Composable fun ReplacementButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( shape = ReplacementTheme.shapes.component, onClick = onClick, modifier = modifier, content = { ProvideTextStyle( value = ReplacementTheme.typography.body ) { content() } } ) }
بعد ذلك، عليك استبدال استخدامات Button
بـ ReplacementButton
في المواضع المناسبة.
@Composable fun ReplacementApp() { ReplacementTheme { /*...*/ ReplacementButton(onClick = { /* ... */ }) { /* ... */ } } }
تنفيذ نظام تصميم مخصّص بالكامل
قد تحتاج إلى استبدال "تخصيص التصميم المتعدد الأبعاد" بنظام تصميم مخصّص بالكامل.
ضَع في اعتبارك أنّ MaterialTheme
يوفّر الأنظمة التالية:
-
Colors
وTypography
وShapes
: أنظمة تخصيص التصميم المتعدد الأبعاد TextSelectionColors
: الألوان المستخدَمة لتحديد النص بواسطةText
وTextField
-
Ripple
وRippleTheme
: تنفيذ الموادIndication
إذا أردت مواصلة استخدام "مكوّنات Material"، عليك استبدال بعض هذه الأنظمة في المظهر أو المظاهر المخصّصة، أو التعامل مع الأنظمة في المكوّنات لتجنُّب السلوك غير المرغوب فيه.
ومع ذلك، لا تقتصر أنظمة التصميم على المفاهيم التي يعتمد عليها Material. يمكنك تعديل الأنظمة الحالية وإضافة أنظمة جديدة تمامًا، مع فئات وأنواع جديدة، لجعل المفاهيم الأخرى متوافقة مع السمات.
في الرمز التالي، نصمّم نظام ألوان مخصّصًا يتضمّن تدرّجات
(List<Color>
)، ونضمِّن نظام أنواع، ونقدّم نظام ارتفاع جديدًا،
ونستثني الأنظمة الأخرى التي توفّرها MaterialTheme
:
@Immutable data class CustomColors( val content: Color, val component: Color, val background: List<Color> ) @Immutable data class CustomTypography( val body: TextStyle, val title: TextStyle ) @Immutable data class CustomElevation( val default: Dp, val pressed: Dp ) val LocalCustomColors = staticCompositionLocalOf { CustomColors( content = Color.Unspecified, component = Color.Unspecified, background = emptyList() ) } val LocalCustomTypography = staticCompositionLocalOf { CustomTypography( body = TextStyle.Default, title = TextStyle.Default ) } val LocalCustomElevation = staticCompositionLocalOf { CustomElevation( default = Dp.Unspecified, pressed = Dp.Unspecified ) } @Composable fun CustomTheme( /* ... */ content: @Composable () -> Unit ) { val customColors = CustomColors( content = Color(0xFFDD0D3C), component = Color(0xFFC20029), background = listOf(Color.White, Color(0xFFF8BBD0)) ) val customTypography = CustomTypography( body = TextStyle(fontSize = 16.sp), title = TextStyle(fontSize = 32.sp) ) val customElevation = CustomElevation( default = 4.dp, pressed = 8.dp ) CompositionLocalProvider( LocalCustomColors provides customColors, LocalCustomTypography provides customTypography, LocalCustomElevation provides customElevation, content = content ) } // Use with eg. CustomTheme.elevation.small object CustomTheme { val colors: CustomColors @Composable get() = LocalCustomColors.current val typography: CustomTypography @Composable get() = LocalCustomTypography.current val elevation: CustomElevation @Composable get() = LocalCustomElevation.current }
استخدام مكوّنات Material
عندما لا يتوفّر MaterialTheme
، سيؤدي استخدام مكونات Material كما هي إلى ظهور قيم غير مرغوب فيها للألوان والأنواع والأشكال والسلوكيات في Material.
إذا أردت استخدام قيم مخصّصة في المكوّنات، يمكنك تضمينها في دوال قابلة للإنشاء خاصة بك، مع ضبط القيم مباشرةً للنظام ذي الصلة، وعرض القيم الأخرى كمعلَمات للمكوّن القابل للإنشاء الذي يحتويها.
ننصحك بالوصول إلى القيم التي تحدّدها من تصميمك المخصّص.
بدلاً من ذلك، إذا كان المظهر لا يوفّر Color
أو TextStyle
أو Shape
أو أنظمة أخرى، يمكنك ترميزها بشكل ثابت.
@Composable fun CustomButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( containerColor = CustomTheme.colors.component, contentColor = CustomTheme.colors.content, disabledContainerColor = CustomTheme.colors.content .copy(alpha = 0.12f) .compositeOver(CustomTheme.colors.component), disabledContentColor = CustomTheme.colors.content .copy(alpha = 0.38f) ), shape = ButtonShape, elevation = ButtonDefaults.elevatedButtonElevation( defaultElevation = CustomTheme.elevation.default, pressedElevation = CustomTheme.elevation.pressed /* disabledElevation = 0.dp */ ), onClick = onClick, modifier = modifier, content = { ProvideTextStyle( value = CustomTheme.typography.body ) { content() } } ) } val ButtonShape = RoundedCornerShape(percent = 50)
إذا كنت قد أضفت أنواعًا جديدة من الفئات، مثل List<Color>
لتمثيل التدرجات، قد يكون من الأفضل تنفيذ المكوّنات من البداية بدلاً من تضمينها. للاطّلاع على مثال، راجِع
JetsnackButton
من نموذج Jetsnack.
أفلام مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون JavaScript غير مفعّلة
- Material Design 3 في Compose
- نقل البيانات من Material 2 إلى Material 3 في Compose
- بنية المظهر في Compose