اگرچه Material سیستم طراحی توصیهشده ما است و Jetpack Compose پیادهسازی Material را ارائه میدهد، مجبور نیستید از آن استفاده کنید. «متریال» کاملاً براساس میاناهای برنامهسازی کاربردی عمومی ساخته شده است، بنابراین میتوانید سیستم طراحی خودتان را به همین روش ایجاد کنید.
چندین رویکرد میتوانید اتخاذ کنید:
-
MaterialThemeرا با مقادیر زمینهسازی اضافی گسترش دهید. - جایگزین کردن یک یا چند سیستم Material —
Colors،Typography، یاShapes— با پیادهسازیهای سفارشی درحالیکه بقیه را حفظ میکنید. - برای جایگزین کردن
MaterialTheme، سیستم طراحی کاملاً سفارشی پیادهسازی کنید.
همچنین ممکن است بخواهید به استفاده از عناصر Material با سیستم طراحی سفارشی ادامه دهید. انجام این کار ممکن است اما باید نکاتی را درنظر داشته باشید تا با رویکردی که اتخاذ کردهاید مطابقت داشته باشد.
برای آشنایی بیشتر با ساختارهای سطح پایینتر و میاناهای برنامهسازی کاربردی که MaterialTheme
و سیستمهای طراحی سفارشی استفاده میکنند، راهنمای ساختار درونمایه در Compose را بررسی کنید.
گسترش موضوعدهی Material
«ترکیب 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»، مقادیر 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»، ممکن است بخواهید یک یا چند سیستم — 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
بههمان شکل ممکن است منجر به مقادیر ناخواسته رنگ، نوع، یا شکل 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: سیستمهای موضوعیسازی Material -
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 }
استفاده از عناصر 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 نگاهی بیندازید.
توصیهشده برای شما
- توجه: نوشتار پیوند وقتی جاوا اسکریپت خاموش است نمایش داده میشود
- Material Design 3 در Compose
- انتقال از Material 2 به Material 3 در Compose
- آناتومی زمینه در «نوشتن»