Material হল আমাদের সাজেস্ট করা ডিজাইন সিস্টেম এবং Jetpack Compose-এ Material-এর ইমপ্লিমেন্টেশন থাকে, তবে আপনাকে এটি ব্যবহার করতে বাধ্য করা হয় না। Material সম্পূর্ণভাবে পাবলিক API-এর উপর ভিত্তি করে তৈরি করা হয়েছে, তাই একই পদ্ধতিতে আপনিও নিজের ডিজাইন সিস্টেম তৈরি করতে পারবেন।
আপনি বিভিন্ন উপায়ে এটি করতে পারেন:
- অতিরিক্ত থিমিং
ভ্যালু সহ এক্সটেন্ড
MaterialThemeকরুন। - এক বা একাধিক Material সিস্টেম —
Colors,TypographyবাShapes— কাস্টম ইমপ্লিমেন্টেশনের মাধ্যমে রিপ্লেস করুন, তবে অন্যগুলি রেখে দিন। MaterialTheme-এর পরিবর্তে সম্পূর্ণ কাস্টম ডিজাইন সিস্টেম প্রয়োগ করুন।
এছাড়াও, আপনি কাস্টম ডিজাইন সিস্টেমের সাথে Material কম্পোনেন্ট ব্যবহার করা চালিয়ে যেতে পারেন। এটি করা সম্ভব, তবে আপনার নেওয়া পদক্ষেপের সাথে মানানসই করার জন্য কিছু বিষয় মাথায় রাখতে হবে।
MaterialTheme
এবং কাস্টম ডিজাইন সিস্টেমের ব্যবহার করা লোয়ার-লেভেল কনস্ট্রাক্ট ও API সম্পর্কে আরও জানতে, Compose-এ থিমের অ্যানাটমি গাইড দেখুন।
মেটেরিয়াল থিমিং এক্সটেন্ড করা
Material নির্দেশিকা মেনে চলার জন্য এটিকে সহজবোধ্য ও টাইপ-সেফ করতে, Compose Material, 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 ব্যবহার API-এর সাথে সামঞ্জস্য প্রদান করে। 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 ব্যবহারের API-এর মতো। এছাড়াও, এটি একাধিক থিম সাপোর্ট করে
কারণ আপনি MaterialTheme-এর মতো একই উপায়ে ExtendedTheme-কে নেস্ট করতে পারেন।
Material কম্পোনেন্ট ব্যবহার করা
মেটেরিয়াল থিমিং এক্সটেন্ড করার সময়, আগে থেকে থাকা MaterialTheme ভ্যালু বজায় থাকে
এবং মেটেরিয়াল কম্পোনেন্ট এখনও যুক্তিসঙ্গত ডিফল্ট ভ্যালু থাকে।
কম্পোনেন্টে বর্ধিত ভ্যালু ব্যবহার করতে চাইলে, সেগুলিকে আপনার নিজস্ব কম্পোজ করার উপযুক্ত ফাংশনে র্যাপ করুন, আপনি যে ভ্যালু পরিবর্তন করতে চান তা সরাসরি সেট করুন এবং অন্যান্য ভ্যালুকে কন্টেন করা কম্পোজ করার উপযুক্ত ফাংশনে প্যারামিটার হিসেবে এক্সপোজ করুন:
@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 থিমিং এক্সটেন্ড করার পরিবর্তে, আপনি কাস্টম ইমপ্লিমেন্টেশনের মাধ্যমে এক বা একাধিক
সিস্টেম — 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: মেটেরিয়াল থিমিং সিস্টেমTextSelectionColors:Text-এর মাধ্যমে টেক্সট বেছে নেওয়ার জন্য ব্যবহৃত রঙ এবংTextFieldRippleও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> যা
গ্রেডিয়েন্টকে রিপ্রেজেন্ট করে — তাহলে সেগুলিকে র্যাপ করার পরিবর্তে
প্রথম থেকে কম্পোনেন্ট প্রয়োগ করা ভালো হতে পারে। যেমন, Jetsnack স্যাম্পেল থেকে
JetsnackButton
দেখুন।
আপনার জন্য সাজেস্ট করা হয়েছে
- মনে রাখবেন: জাভাস্ক্রিপ্ট বন্ধ থাকলে লিঙ্ক টেক্সট দেখানো হয়
- Compose-এ Material Design 3
- Compose-এ Material 2 থেকে Material 3-তে মাইগ্রেট করা
- Compose-এ থিমের গঠন