মেশ গ্রেডিয়েন্ট

মেশ গ্রেডিয়েন্ট প্যাচের একটি ২ডি গ্রিড ব্যবহার করে জটিল ও বহু-দিকনির্দেশক রঙের রূপান্তর তৈরি করে। লিনিয়ার বা রেডিয়াল গ্রেডিয়েন্টের মতো নয়, মেশ গ্রেডিয়েন্ট একটি গ্রিড জুড়ে মসৃণভাবে রঙগুলোকে বিন্যস্ত করে। আপনার ইউজার ইন্টারফেসে সাবলীল ও স্বাভাবিক নান্দনিক উপাদান তৈরি করতে মেশ গ্রেডিয়েন্ট ব্যবহার করুন।

একটি মেশ গ্রেডিয়েন্টের উদাহরণ, যেখানে এর বর্তমান মেশ গ্রেডিয়েন্ট পয়েন্টগুলো প্রদর্শন করা হয়েছে।
চিত্র ১। একটি মেশ গ্রেডিয়েন্টের উদাহরণ এবং এর বর্তমান মেশ গ্রেডিয়েন্ট পয়েন্টগুলো প্রদর্শন।

মূল ধারণা

একটি মেশ গ্রেডিয়েন্ট তৈরি করতে, গ্রিডের মাত্রা, শীর্ষবিন্দু এবং বিন্দুগুলোর মধ্যে রঙের পরিবর্তন নির্ধারণ করুন:

  • গ্রিডের মাত্রা: মেশটি উল্লম্ব এবং অনুভূমিক অক্ষ বরাবর বিভিন্ন অংশে বিভক্ত থাকে। rows এবং columns একটি গ্রিডে (সারি+১)×(কলাম+১) টি শীর্ষবিন্দু থাকে। উদাহরণস্বরূপ, একটি ১×১ মেশ ৪টি শীর্ষবিন্দু নিয়ে গঠিত যা একটি অংশ তৈরি করে।
  • নর্মালাইজড স্থানাঙ্ক: সকল ভার্টেক্স পজিশন একটি নর্মালাইজড স্থানাঙ্ক ব্যবস্থা ব্যবহার করে, যেখানে (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)
)

বক্র শীর্ষ-বাম বিন্দু সহ মেশ গ্রেডিয়েন্ট।
চিত্র ৩। একটি বেজিয়ার কন্ট্রোল পয়েন্ট দিয়ে উপরের-বাম শীর্ষবিন্দুটিকে বক্র করুন।

উন্নত গ্রিড তৈরি করুন

এই উদাহরণটিতে একটি ৩ বাই ৩ গ্রিড দেখানো হয়েছে, অর্থাৎ এখানে ১৬টি বিন্দু নির্দিষ্ট করতে হবে, যেখানে মধ্যবর্তী বিন্দুগুলো ভিন্ন ভিন্ন অফসেট দিয়ে সেট করা হয়েছে:

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 ল্যাম্বডা প্যারামিটারটি একটি 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)
)

চিত্র ৫. অ্যানিমেশন দেখানোর জন্য পয়েন্টসহ অ্যানিমেটেড মেশ গ্রেডিয়েন্ট।