در حالی که Material سیستم طراحی پیشنهادی ما است و Jetpack Compose پیاده سازی Material را ارسال می کند، شما مجبور به استفاده از آن نیستید. متریال به طور کامل بر روی API های عمومی ساخته شده است، بنابراین می توانید سیستم طراحی خود را به همان شیوه ایجاد کنید.
چندین رویکرد وجود دارد که ممکن است اتخاذ کنید:
- گسترش
MaterialTheme
با مقادیر طرح زمینه اضافی - جایگزینی یک یا چند سیستم متریال -
Colors
،Typography
یاShapes
- با پیادهسازیهای سفارشی، در عین حال حفظ سایرین - پیاده سازی یک سیستم طراحی کاملاً سفارشی برای جایگزینی
MaterialTheme
همچنین ممکن است بخواهید به استفاده از اجزای Material با یک سیستم طراحی سفارشی ادامه دهید. انجام این کار ممکن است، اما مواردی وجود دارد که باید در نظر داشته باشید تا با رویکردی که در پیش گرفته اید مطابقت داشته باشد.
برای کسب اطلاعات بیشتر در مورد ساختارهای سطح پایین و API های مورد استفاده توسط MaterialTheme
و سیستم های طراحی سفارشی، آناتومی یک موضوع را در راهنمای Compose بررسی کنید.
گسترش تم مواد
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)
این یک سازگاری با API های استفاده از MaterialTheme
را فراهم می کند. نمونه ای از این تعریف شده توسط خود Compose، surfaceColorAtElevation
است که رنگ سطحی را که باید بسته به ارتفاع استفاده شود، تعیین می کند.
رویکرد دیگر تعریف یک تم گسترده است که MaterialTheme
و مقادیر آن را "پیچیده" می کند.
فرض کنید می خواهید دو رنگ اضافی اضافه کنید - caution
و onCaution
، یک رنگ زرد که برای اقدامات نیمه خطرناک استفاده می شود - در حالی که رنگ های مواد موجود را حفظ کنید:
@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 }
این شبیه به APIهای استفاده از MaterialTheme
است. همچنین از چندین تم پشتیبانی میکند، زیرا میتوانید ExtendedTheme
را به همان روش MaterialTheme
در درون خود قرار دهید.
از اجزای متریال استفاده کنید
هنگام گسترش Material Theme، مقادیر MaterialTheme
موجود حفظ میشوند و اجزای Material همچنان پیشفرضهای معقولی دارند.
اگر میخواهید از مقادیر توسعهیافته در کامپوننتها استفاده کنید، آنها را در توابع ترکیبپذیر خود بپیچید، مستقیماً مقادیری را که میخواهید تغییر دهید تنظیم کنید، و دیگران را بهعنوان پارامتر در معرض composable حاوی قرار دهید:
@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 = { /* ... */ }) { /* ... */ } } }
سیستم های فرعی مواد را جایگزین کنید
به جای گسترش تم مواد، ممکن است بخواهید یک یا چند سیستم - 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 }
از اجزای متریال استفاده کنید
هنگامی که یک یا چند سیستم از 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 = { /* ... */ }) { /* ... */ } } }
پیاده سازی یک سیستم طراحی کاملا سفارشی
ممکن است بخواهید Material Theming را با یک سیستم طراحی کاملاً سفارشی جایگزین کنید. در نظر بگیرید که MaterialTheme
سیستم های زیر را ارائه می دهد:
-
Colors
،Typography
، وShapes
: سیستمهای تمبندی مواد -
TextSelectionColors
: رنگهایی که برای انتخاب متن توسطText
وTextField
استفاده میشوند -
Ripple
وRippleTheme
: اجرای موادIndication
اگر میخواهید به استفاده از مؤلفههای 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 }
از اجزای متریال استفاده کنید
وقتی MaterialTheme
وجود نداشته باشد، استفاده از مولفههای Material همانطور که هست منجر به مقادیر ناخواسته رنگ، نوع و شکل مواد و رفتار نشانه میشود.
اگر میخواهید از مقادیر سفارشی در کامپوننتها استفاده کنید، آنها را در توابع ترکیبپذیر خود بپیچید، مستقیماً مقادیر را برای سیستم مربوطه تنظیم کنید، و دیگران را بهعنوان پارامتر در معرض composable حاوی قرار دهید.
توصیه می کنیم به مقادیری که از طرح زمینه سفارشی خود تنظیم کرده اید دسترسی داشته باشید. از طرف دیگر، اگر تم شما 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 بیندازید.
برای شما توصیه می شود
- توجه: وقتی جاوا اسکریپت خاموش است، متن پیوند نمایش داده می شود
- متریال دیزاین 3 در Compose
- از Material 2 به Material 3 در Compose مهاجرت کنید
- آناتومی یک تم در Compose