যদিও ম্যাটেরিয়াল আমাদের প্রস্তাবিত ডিজাইন সিস্টেম এবং জেটপ্যাক কম্পোজে ম্যাটেরিয়ালের একটি ইমপ্লিমেন্টেশন অন্তর্ভুক্ত রয়েছে, আপনাকে এটি ব্যবহার করতে বাধ্য করা হচ্ছে না। ম্যাটেরিয়াল সম্পূর্ণরূপে পাবলিক এপিআই-এর উপর ভিত্তি করে তৈরি, তাই একই পদ্ধতিতে আপনার নিজস্ব ডিজাইন সিস্টেম তৈরি করা সম্ভব।
আপনি কয়েকটি পন্থা অবলম্বন করতে পারেন:
- অতিরিক্ত থিমিং মান দিয়ে
MaterialThemeপ্রসারিত করুন । - অন্যগুলো অপরিবর্তিত রেখে এক বা একাধিক ম্যাটেরিয়াল সিস্টেম —
Colors,TypographyবাShapes—কাস্টম ইমপ্লিমেন্টেশন দিয়ে প্রতিস্থাপন করুন। -
MaterialThemeপ্রতিস্থাপন করতে একটি সম্পূর্ণ কাস্টম ডিজাইন সিস্টেম প্রয়োগ করুন ।
আপনি একটি কাস্টম ডিজাইন সিস্টেমের সাথেও ম্যাটেরিয়াল কম্পোনেন্ট ব্যবহার চালিয়ে যেতে চাইতে পারেন। এটি করা সম্ভব, তবে আপনার গৃহীত পদ্ধতির সাথে সামঞ্জস্য রাখার জন্য কিছু বিষয় মনে রাখতে হবে।
MaterialTheme এবং কাস্টম ডিজাইন সিস্টেম দ্বারা ব্যবহৃত নিম্ন-স্তরের গঠন ও API সম্পর্কে আরও জানতে, “ Anatomy of a theme in Compose” গাইডটি দেখুন।
উপাদান থিমিং প্রসারিত করুন
কম্পোজ মেটেরিয়াল, মেটেরিয়াল থিমিং-এর আদলে তৈরি করা হয়েছে, যাতে মেটেরিয়াল নির্দেশিকাগুলো অনুসরণ করা সহজ এবং টাইপ-সেফ হয়। তবে, অতিরিক্ত ভ্যালু দিয়ে কালার, টাইপোগ্রাফি এবং শেপ সেটগুলোকে প্রসারিত করা সম্ভব। এর সবচেয়ে সহজ উপায় হলো এক্সটেনশন প্রোপার্টি যোগ করা:
// 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 , যেখানে অনকশন হলো আধা-বিপজ্জনক কাজের জন্য ব্যবহৃত হলুদ রঙ।
@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 কে নেস্ট করতে পারেন।
উপাদান ব্যবহার করুন
ম্যাটেরিয়াল থিমিং সম্প্রসারণ করার সময়, বিদ্যমান 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 = { /* ... */ }) { /* ... */ } } }
উপাদান উপ-সিস্টেমগুলি প্রতিস্থাপন করুন
ম্যাটেরিয়াল থিমিং সম্প্রসারণ করার পরিবর্তে, আপনি অন্য সিস্টেমগুলো অপরিবর্তিত রেখে 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 কম্পোনেন্টগুলো সরাসরি ব্যবহার করলে অবাঞ্ছিত 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ম্যাটেরিয়াল বাস্তবায়ন
আপনি যদি ম্যাটেরিয়াল কম্পোনেন্ট ব্যবহার চালিয়ে যেতে চান, তবে অনাকাঙ্ক্ষিত আচরণ এড়াতে আপনাকে অবশ্যই আপনার কাস্টম থিমে এই সিস্টেমগুলোর কিছু প্রতিস্থাপন করতে হবে অথবা আপনার কম্পোনেন্টগুলোর মধ্যেই সিস্টেমগুলোকে নিয়ন্ত্রণ করতে হবে।
তবে, ডিজাইন সিস্টেমগুলো শুধু ম্যাটেরিয়ালের নির্ভর করা ধারণাগুলোর মধ্যেই সীমাবদ্ধ নয়। আপনি বিদ্যমান সিস্টেমগুলোকে পরিবর্তন করতে পারেন এবং নতুন ক্লাস ও টাইপসহ সম্পূর্ণ নতুন সিস্টেম চালু করতে পারেন, যাতে অন্যান্য ধারণাগুলো থিমের সাথে সামঞ্জস্যপূর্ণ হয়।
নিম্নলিখিত কোডে, আমরা গ্রেডিয়েন্ট ( 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 কম্পোনেন্টগুলো সরাসরি ব্যবহার করলে 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 2 থেকে Material 3-তে স্থানান্তরিত করুন
- কম্পোজে একটি থিমের গঠন