मेश ग्रेडिएंट

मेश ग्रेडिएंट, पैच की 2D ग्रिड का इस्तेमाल करके, कई दिशाओं में रंग के ट्रांज़िशन बनाते हैं. लाइनर या रेडियल ग्रेडिएंट के उलट, मेश ग्रेडिएंट, ग्रिड में रंगों को आसानी से इंटरपोलेट करते हैं. मेश ग्रेडिएंट का इस्तेमाल करके, अपने यूज़र इंटरफ़ेस में फ़्लूड और ऑर्गैनिक एस्थेटिक एलिमेंट बनाएं.

मेश ग्रेडिएंट का उदाहरण, जिसमें इसके मौजूदा मेश ग्रेडिएंट पॉइंट दिखाए गए हैं.
पहली इमेज. मेश ग्रेडिएंट का एक उदाहरण, जिसमें उसके मौजूदा मेश ग्रेडिएंट पॉइंट दिखाए गए हैं.

मुख्य सिद्धांत

मेश ग्रेडिएंट बनाने के लिए, ग्रिड के डाइमेंशन, वर्टिकल, और पॉइंट के बीच रंग के ट्रांज़िशन तय करें:

  • ग्रिड के डाइमेंशन: मेश को वर्टिकल और हॉरिज़ॉन्टल ऐक्सिस के हिसाब से पैच में बांटा जाता है. rows और columns की ग्रिड में (rows+1)×(columns+1) वर्टिकल होते हैं. उदाहरण के लिए, 1×1 मेश में चार वर्टिकल होते हैं, जो एक पैच बनाते हैं.
  • नॉर्मलाइज़ किए गए कोऑर्डिनेट: सभी वर्टिकल की पोज़िशन के लिए, नॉर्मलाइज़ किए गए कोऑर्डिनेट सिस्टम का इस्तेमाल किया जाता है. इसमें (0f, 0f) का मतलब, ड्रॉइंग बाउंड के सबसे ऊपर बाईं ओर और (1f, 1f) का मतलब, सबसे नीचे दाईं ओर होता है.
  • बेज़ियर कंट्रोल पॉइंट (टैंजेंट): हर वर्टिकल में, ज़्यादा से ज़्यादा चार बेज़ियर कंट्रोल पॉइंट हो सकते हैं. हालांकि, यह ज़रूरी नहीं है. ये टैंजेंट, आस-पास के वर्टिकल के बीच एज कर्वेचर तय करते हैं. अगर Offset.Unspecified का इस्तेमाल किया जाता है, तो Compose, टैंजेंट का अनुमान लगाता है, ताकि पैच के बीच आसानी से ट्रांज़िशन हो सके. चार वर्टिकल और उनके कंट्रोल पॉइंट से बनी हर ग्रिड सेल, बेज़ियर पैच जनरेट करती है.
  • कलर इंटरपोलेशन: फ़्रेमवर्क, मुख्य वर्टिकल के बीच के रंगों का हिसाब लगाता है. बेहतर तरीके से रंग बदलने के लिए, कैटमुल-रोम इंटरपोलेशन के लिए hasBicubicColor को true पर सेट करें. वहीं, बाइलिनियर इंटरपोलेशन के लिए, इसे false पर सेट करें.

MeshGradientPainter से ड्रॉ करना

Jetpack Compose में, मेश ग्रेडिएंट रेंडर करने के लिए, MeshGradientPainter का इस्तेमाल करें. MeshGradientPainter, कैनवस पर ड्रॉ करता है.

सामान्य मेश ग्रेडिएंट बनाना

बेसिक स्टैटिक मेश ग्रेडिएंट बनाने के लिए, उसके डाइमेंशन तय करके MeshGradientPainter को शुरू करें. साथ ही, कॉन्फ़िगरेशन ब्लॉक में setVertex फ़ंक्शन का इस्तेमाल करके, कॉर्नर पॉइंट की पोज़िशन तय करें और उन्हें रंग असाइन करें.

val rows = 1
val columns = 1

val gradientPainter = remember {
    MeshGradientPainter(rows, columns) {
        // Parameters: row, column, position, color
        setVertex(0, 0, Offset(0f, 0f), Color.Red)     // Top-Left
        setVertex(0, 1, Offset(1f, 0f), Color.Blue)    // Top-Right
        setVertex(1, 0, Offset(0f, 1f), Color.Green)   // Bottom-Left
        setVertex(1, 1, Offset(1f, 1f), Color.Yellow)  // Bottom-Right
    }
}

Box(
    modifier = modifier
        .aspectRatio(16/9f)
        .fillMaxWidth()
        .paint(gradientPainter)
)

हर कोने पर चार रंगों वाला बेसिक मेश ग्रेडिएंट
दूसरी इमेज. चार रंगों वाला एक बेसिक मेश ग्रेडिएंट. इसमें हर कॉर्नर के लिए, चार में से एक रंग सेट किया गया है.

बेज़ियर कंट्रोल पॉइंट का इस्तेमाल करना

डिफ़ॉल्ट रूप से, मेश जनरेटर, ग्रिड ट्रांज़िशन को आसानी से बनाए रखने के लिए, मुश्किल कैलकुलेशन को हैंडल करता है. हालांकि, अगर आपको चुनिंदा तौर पर, कुछ रंग सेक्शन को पुश, पुल या शार्प पिंच करना है, तो किसी भी वर्टिकल पर टैंजेंट को साफ़ तौर पर पसंद के मुताबिक बनाया जा सकता है.

कंट्रोल ऑफ़सेट, होस्ट वर्टिकल की पोज़िशन के हिसाब से मेज़र किए जाते हैं.

val customTangentPainter = remember {
    MeshGradientPainter(rows = 1, columns = 1) {
        // Tweak the top-left vertex to curve outwards to the right and bottom
        setVertex(
            row = 0,
            column = 0,
            position = Offset(0f, 0f),
            color = Color.Magenta,
            rightControlPoint = Offset(0.4f, 0.1f),
            bottomControlPoint = Offset(0.1f, 0.4f)
        )

        // Other points can remain unspecified to use default inferred fallback tangents
        setVertex(0, 1, Offset(1f, 0f), Color.Cyan)
        setVertex(1, 0, Offset(0f, 1f), Color.Blue)
        setVertex(1, 1, Offset(1f, 1f), Color.Black)
    }
}
Box(
    modifier = modifier
        .aspectRatio(16/9f)
        .fillMaxWidth()
        .paint(customTangentPainter)
)

इस इमेज में, मेष ग्रेडिएंट दिख रहा है. इसका सबसे ऊपर बायां कोना घुमावदार है.
तीसरी इमेज. बेज़ियर कंट्रोल पॉइंट की मदद से, सबसे ऊपर बाईं ओर मौजूद वर्टिकल को घुमाएं.

ऐडवांस ग्रिड बनाना

इस उदाहरण में, 3x3 ग्रिड दिखाया गया है. इसका मतलब है कि 16 पॉइंट तय करने होंगे. साथ ही, बीच के पॉइंट को अलग-अलग ऑफ़सेट के साथ सेट करना होगा:

val points = remember {
    listOf(
        Offset(0.0f, 0.0f), Offset(0.3f, 0.0f), Offset(0.7f, 0.0f), Offset(1.0f, 0.0f),
        Offset(0.0f, 0.3f), Offset(0.2f, 0.4f), Offset(0.7f, 0.2f), Offset(1.0f, 0.3f),
        Offset(0.0f, 0.7f), Offset(0.3f, 0.8f), Offset(0.7f, 0.6f), Offset(1.0f, 0.7f),
        Offset(0.0f, 1.0f), Offset(0.3f, 1.0f), Offset(0.7f, 1.0f), Offset(1.0f, 1.0f)
    )
}

val gradientPainter = remember {
    MeshGradientPainter(rows = 3, columns = 3) {
        // Row 0
        setVertex(0, 0, points[0], yellow)
        setVertex(0, 1, points[1], orange)
        setVertex(0, 2, points[2], yellow)
        setVertex(0, 3, points[3], purple)

        // Row 1
        setVertex(1, 0, points[4], pink)
        setVertex(1, 1, points[5], yellow)
        setVertex(1, 2, points[6], pink)
        setVertex(1, 3, points[7], purple)

        // Row 2
        setVertex(2, 0, points[8], indigo)
        setVertex(2, 1, points[9], pink)
        setVertex(2, 2, points[10], purple)
        setVertex(2, 3, points[11], indigo)

        // Row 3
        setVertex(3, 0, points[12], purple)
        setVertex(3, 1, points[13], indigo)
        setVertex(3, 2, points[14], pink)
        setVertex(3, 3, points[15], yellow)
    }
}

Box(
    modifier = modifier.padding(32.dp)
        .aspectRatio(16 / 9f)
        .fillMaxWidth()
        .paint(gradientPainter)
        // ...
)

बेज़ियर कंट्रोल पॉइंट और वेव कलर वाला मेश ग्रेडिएंट. साथ ही, इसके ऊपर मेश पॉइंट दिखाए गए हैं.
चौथी इमेज. बेज़ियर कंट्रोल पॉइंट और वेव कलर वाला मेश ग्रेडिएंट. इसके ऊपर, मेश पॉइंट दिखाए गए हैं.

मेश ग्रेडिएंट में ऐनिमेशन जोड़ना

MeshGradientPainter का block lambda पैरामीटर, DrawScope में एक्ज़ीक्यूट होता है. इसलिए, यह बदलाव किए जा सकने वाले स्टेट को पढ़ और देख सकता है. शेडर या बिटमैप को फिर से असाइन किए बिना, पोज़िशन या रंगों में समय के साथ ऐनिमेशन जोड़ा जा सकता है.

val infiniteTransition = rememberInfiniteTransition(label = "meshMovement")
val animatedOffset by infiniteTransition.animateFloat(
    initialValue = -0.1f,
    targetValue = 0.1f,
    animationSpec = infiniteRepeatable(
        animation = tween(2500, easing = LinearEasing),
        repeatMode = RepeatMode.Reverse
    ),
    label = "offset"
)

val coral = Color(255, 90, 90)
val peach = Color(255, 139, 90)
val amber = Color(255, 169, 90)
val sunshine = Color(255, 212, 90)
val indigo = Color(0xFF5856D6)
val pink = Color(0xFFFF2D55)


val gradientPainter = remember {
    MeshGradientPainter(rows = 3, columns = 3) {
        // Row 0
        setVertex(0, 0, Offset(0.0f, 0.0f), indigo)
        setVertex(0, 1, Offset(0.3f, 0.0f), peach)
        setVertex(0, 2, Offset(0.7f, 0.0f), amber)
        setVertex(0, 3, Offset(1.0f, 0.0f), sunshine)
        // Row 1
        setVertex(1, 0, Offset(0.0f, 0.3f), pink)
        setVertex(1, 1, Offset(0.2f, 0.4f) + Offset(animatedOffset, animatedOffset), coral)
        setVertex(1, 2, Offset(0.7f, 0.2f) + Offset(animatedOffset, animatedOffset), peach)
        setVertex(1, 3, Offset(1.0f, 0.3f), indigo)

        // Row 2
        setVertex(2, 0, Offset(0.0f, 0.7f), coral)
        setVertex(2, 1, Offset(0.3f, 0.8f) + Offset(animatedOffset, 0f), pink)
        setVertex(2, 2, Offset(0.7f, 0.6f) + Offset(animatedOffset, 0f), sunshine)
        setVertex(2, 3, Offset(1.0f, 0.7f), amber)

        // Row 3
        setVertex(3, 0, Offset(0.0f, 1.0f), sunshine)
        setVertex(3, 1, Offset(0.3f, 1.0f), amber)
        setVertex(3, 2, Offset(0.7f, 1.0f), pink)
        setVertex(3, 3, Offset(1.0f, 1.0f), indigo)
    }
}


Box(
    modifier = modifier.padding(32.dp)
        .safeContentPadding()
        .aspectRatio(16 / 9f)
        .fillMaxWidth()
        .paint(gradientPainter)
)

पांचवी इमेज. ऐनिमेटेड मेश ग्रेडिएंट, जिसमें ऐनिमेशन दिखाने के लिए पॉइंट शामिल हैं.