কম্পোজে কাস্টম ডিজাইন সিস্টেম

যদিও উপাদান হল আমাদের প্রস্তাবিত ডিজাইন সিস্টেম এবং জেটপ্যাক কম্পোজ উপাদানের একটি বাস্তবায়ন চালায়, আপনি এটি ব্যবহার করতে বাধ্য হন না। উপাদান সম্পূর্ণরূপে পাবলিক API তে নির্মিত, তাই একই পদ্ধতিতে আপনার নিজস্ব ডিজাইন সিস্টেম তৈরি করা সম্ভব।

আপনি নিতে পারেন বিভিন্ন পদ্ধতি আছে:

আপনি একটি কাস্টম ডিজাইন সিস্টেমের সাথে উপাদান উপাদান ব্যবহার চালিয়ে যেতে চাইতে পারেন। এটি করা সম্ভব কিন্তু আপনার নেওয়া পদ্ধতির সাথে মানানসই করার জন্য কিছু বিষয় মাথায় রাখতে হবে।

MaterialTheme এবং কাস্টম ডিজাইন সিস্টেম দ্বারা ব্যবহৃত নিম্ন-স্তরের নির্মাণ এবং API সম্পর্কে আরও জানতে, কম্পোজ গাইডে একটি থিমের অ্যানাটমি দেখুন।

উপাদান থিমিং প্রসারিত

উপাদান নির্দেশিকা অনুসরণ করা সহজ এবং টাইপ-নিরাপদ করার জন্য উপাদানগুলিকে ঘনিষ্ঠভাবে মডেলগুলি উপাদান থিমিং তৈরি করুন৷ যাইহোক, অতিরিক্ত মান সহ রঙ, টাইপোগ্রাফি এবং আকৃতির সেটগুলি প্রসারিত করা সম্ভব।

সবচেয়ে সহজ পদ্ধতি হল এক্সটেনশন বৈশিষ্ট্য যোগ করা:

// Use with MaterialTheme.colors.snackbarAction
val Colors.snackbarAction: Color
    get() = if (isLight) 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-এর সাথে ধারাবাহিকতা প্রদান করে। কম্পোজ দ্বারা সংজ্ঞায়িত এর একটি উদাহরণ হল primarySurface , যা Colors.isLight এর উপর নির্ভর করে primary এবং surface মধ্যে একটি প্রক্সি হিসাবে কাজ করে।

আরেকটি পদ্ধতি হল একটি বর্ধিত থিম সংজ্ঞায়িত করা যা MaterialTheme এবং এর মানগুলিকে "মোড়ানো" করে।

ধরুন আপনি দুটি অতিরিক্ত রঙ যোগ করতে চান — tertiary এবং onTertiary — বিদ্যমান উপাদানের রঙগুলি রেখে:

@Immutable
data class ExtendedColors(
    val tertiary: Color,
    val onTertiary: Color
)

val LocalExtendedColors = staticCompositionLocalOf {
    ExtendedColors(
        tertiary = Color.Unspecified,
        onTertiary = Color.Unspecified
    )
}

@Composable
fun ExtendedTheme(
    /* ... */
    content: @Composable () -> Unit
) {
    val extendedColors = ExtendedColors(
        tertiary = Color(0xFFA8EFF0),
        onTertiary = Color(0xFF002021)
    )
    CompositionLocalProvider(LocalExtendedColors provides extendedColors) {
        MaterialTheme(
            /* colors = ..., typography = ..., shapes = ... */
            content = content
        )
    }
}

// Use with eg. ExtendedTheme.colors.tertiary
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.tertiary,
            contentColor = ExtendedTheme.colors.onTertiary
            /* 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 এর এক বা একাধিক সিস্টেম প্রতিস্থাপন করা হয়, ম্যাটেরিয়াল কম্পোনেন্ট যেমন-ই ব্যবহার করা হয়, তখন অবাঞ্ছিত উপাদানের রঙ, প্রকার বা আকৃতির মান হতে পারে।

আপনি যদি উপাদানগুলিতে প্রতিস্থাপনের মানগুলি ব্যবহার করতে চান তবে সেগুলিকে আপনার নিজস্ব কম্পোজেবল ফাংশনে মোড়ানো, প্রাসঙ্গিক সিস্টেমের জন্য মানগুলি সরাসরি সেট করুন এবং অন্যান্য কম্পোজেবলের প্যারামিটার হিসাবে প্রকাশ করুন৷

@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()
            }
        }
    )
}

তারপরে আপনি যেখানে উপযুক্ত সেখানে ReplacementButton দিয়ে Button ব্যবহার প্রতিস্থাপন করবেন।

@Composable
fun ReplacementApp() {
    ReplacementTheme {
        /*...*/
        ReplacementButton(onClick = { /* ... */ }) {
            /* ... */
        }
    }
}

একটি সম্পূর্ণ কাস্টম ডিজাইন সিস্টেম বাস্তবায়ন

আপনি একটি সম্পূর্ণ-কাস্টম ডিজাইন সিস্টেমের সাথে উপাদান থিমিং প্রতিস্থাপন করতে চাইতে পারেন। বিবেচনা করুন যে MaterialTheme নিম্নলিখিত সিস্টেমগুলি প্রদান করে:

  • Colors , Typography , এবং Shapes : উপাদান থিমিং সিস্টেম
  • ContentAlpha : Text এবং Icon জোর দেওয়ার জন্য অস্বচ্ছতার মাত্রা
  • 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 উপস্থিত থাকে না, তখন উপাদানের উপাদানগুলিকে যেমন-যথাযভাবে ব্যবহার করা হয়, তাহলে অবাঞ্ছিত উপাদানের রঙ, প্রকার এবং আকৃতির মান এবং ইঙ্গিত আচরণ হবে।

আপনি যদি উপাদানগুলিতে কাস্টম মানগুলি ব্যবহার করতে চান তবে সেগুলিকে আপনার নিজস্ব কম্পোজেবল ফাংশনে মোড়ানো, প্রাসঙ্গিক সিস্টেমের জন্য মানগুলি সরাসরি সেট করুন এবং অন্যান্য কম্পোজেবলের প্যারামিটার হিসাবে প্রকাশ করুন৷

আমরা আপনাকে আপনার কাস্টম থিম থেকে সেট করা মানগুলি অ্যাক্সেস করার পরামর্শ দিই। বিকল্পভাবে, যদি আপনার থিম 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 = ContentAlpha.disabled)
        ),
        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 দেখুন।

{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}