Jetpack Compose-এর আর্কিটেকচারাল লেয়ারিং

এই পৃষ্ঠায় Jetpack Compose-এর আর্কিটেকচারাল লেয়ারের একটি হাই-লেভেল ওভারভিউ দেওয়া হয়েছে। এছাড়াও, এই ডিজাইনকে প্রভাবিত করে এমন মূল নীতিগুলিও এখানে উল্লেখ করা হয়েছে।

Jetpack Compose কোনও একক, মনোলিথিক প্রোজেক্ট নয়; এটি অসংখ্য মডিউল থেকে তৈরি করা হয়েছে যেগুলি একসাথে অ্যাসেম্বল করে সম্পূর্ণ স্ট্যাক তৈরি করা হয়। Jetpack Compose-এর বিভিন্ন মডিউল সম্পর্কে জানলে আপনি এগুলি করতে পারবেন:

  • আপনার অ্যাপ বা লাইব্রেরি তৈরি করতে অ্যাবস্ট্রাকশনের উপযুক্ত লেভেল ব্যবহার করুন
  • আরও নিয়ন্ত্রণ বা কাস্টমাইজেশনের জন্য কখন আপনি লোয়ার লেভেলে ‘ড্রপ ডাউন’ করতে পারবেন তা জানুন
  • ডিপেন্ডেন্সি কমান

লেয়ার

Jetpack Compose-এর প্রধান লেয়ারগুলি হল:

ছবি ১. Jetpack Compose-এর প্রধান লেয়ার।

প্রতিটি লেয়ার তার নিচের লেয়ারের উপর ভিত্তি করে তৈরি হয় এবং এর মধ্যে বিভিন্ন ফাংশনালিটি একত্রিত করে উচ্চ-লেভেল কম্পোনেন্ট তৈরি করা হয়। প্রতিটি লেয়ার, মডিউল সীমানা যাচাই করতে এবং প্রয়োজন হলে যেকোনও লেয়ার পরিবর্তন করতে, নিচের লেয়ারের পাবলিক API-এর উপর ভিত্তি করে তৈরি হয়। আসুন, আমরা এই লেয়ারগুলি নিচ থেকে উপরের দিকে পরীক্ষা করে দেখি।

রানটাইম
এই মডিউলটি Compose রানটাইমের মৌলিক বিষয়গুলি প্রদান করে, যেমন remember, mutableStateOf, @Composable অ্যানোটেশন এবং SideEffect। আপনি যদি শুধুমাত্র Compose-এর ট্রি ম্যানেজমেন্ট ক্ষমতা চান, UI নয়, তাহলে সরাসরি এই লেয়ারের উপর বিল্ড করার কথা বিবেচনা করতে পারেন।
UI
UI লেয়ার একাধিক মডিউল দিয়ে তৈরি ( ui-text, ui-graphics, ui-tooling, ইত্যাদি)। এইসব মডিউল UI টুলকিটের মূল বিষয়গুলি প্রয়োগ করে, যেমন LayoutNode, Modifier, ইনপুট হ্যান্ডলার, কাস্টম লেআউট ও ড্রয়িং। আপনি এই লেয়ারের উপর ভিত্তি করে তৈরি করার কথা বিবেচনা করতে পারেন, যদি আপনার শুধুমাত্র UI টুলকিটের মৌলিক ধারণা প্রয়োজন হয়।
ফাউন্ডেশন
এই মডিউলটি Compose UI-এর জন্য ডিজাইন সিস্টেম অ্যাগনস্টিক বিল্ডিং ব্লক প্রদান করে, যেমন Row এবং Column, LazyColumn, নির্দিষ্ট জেসচার শনাক্তকরণ ইত্যাদি। আপনি নিজের ডিজাইন সিস্টেম তৈরি করতে ফাউন্ডেশন লেয়ারের উপর ভিত্তি করে তৈরি করার কথা বিবেচনা করতে পারেন।
মেটেরিয়াল
এই মডিউলটি Compose UI-এর জন্য মেটেরিয়াল ডিজাইন সিস্টেমের প্রয়োগ প্রদান করে, যা থিমিং সিস্টেম, স্টাইল করা কম্পোনেন্ট, রিপেল ইন্ডিকেশন, আইকন প্রদান করে। আপনার অ্যাপে Material Design ব্যবহার করার সময় এই লেয়ারের উপর ভিত্তি করে বিল্ড করুন।

ডিজাইন সংক্রান্ত নীতি

Jetpack Compose-এর একটি মূল নীতি হল, কয়েকটি বড় বড় কম্পোনেন্টের পরিবর্তে, ছোট ছোট, নির্দিষ্ট কার্যকারিতা প্রদান করা যা একসাথে অ্যাসেম্বল (বা কম্পোজ) করা যেতে পারে। এই পদ্ধতির অনেক সুবিধা আছে।

কন্ট্রোল

উচ্চতর লেভেলের কম্পোনেন্ট আপনার জন্য আরও বেশি কাজ করে, কিন্তু আপনার কাছে থাকা ডাইরেক্ট কন্ট্রোলের পরিমাণ সীমিত করে। আরও বেশি কন্ট্রোল চাইলে, আপনি আরও নিম্ন লেভেলের কম্পোনেন্ট ব্যবহার করতে পারেন।

যেমন, আপনি যদি কোনও কম্পোনেন্টের রঙ অ্যানিমেট করতে চান, তাহলে animateColorAsState API ব্যবহার করতে পারেন:

val color = animateColorAsState(if (condition) Color.Green else Color.Red)

তবে, আপনি যদি চান যে কম্পোনেন্টটি সবসময় ধূসর হিসেবেই শুরু হোক, তাহলে এই API-এর মাধ্যমে তা করতে পারবেন না। এর পরিবর্তে, আপনি ড্রপ-ডাউন করে নিম্ন লেভেলের Animatable API ব্যবহার করতে পারেন:

val color = remember { Animatable(Color.Gray) }
LaunchedEffect(condition) {
    color.animateTo(if (condition) Color.Green else Color.Red)
}

উচ্চতর লেভেলের animateColorAsState API, নিম্নতর লেভেলের Animatable API-এর উপর ভিত্তি করেই তৈরি করা হয়। নিম্ন লেভেলের API ব্যবহার করা আরও জটিল, তবে এটি আরও বেশি কন্ট্রোল প্রদান করে। আপনার প্রয়োজন অনুযায়ী সবচেয়ে উপযোগী অ্যাবস্ট্রাকশনের লেভেল বেছে নিন।

কাস্টমাইজেশন

ছোট ছোট বিল্ডিং ব্লক থেকে উচ্চতর লেভেলের কম্পোনেন্ট অ্যাসেম্বল করলে, প্রয়োজন হলে কম্পোনেন্ট কাস্টমাইজ করা অনেক সহজ হয়ে যায়। যেমন, মেটেরিয়াল লেয়ারের দেওয়া প্রয়োগ এর Button কথা বিবেচনা করুন:

@Composable
fun Button(
    // …
    content: @Composable RowScope.() -> Unit
) {
    Surface(/* … */) {
        CompositionLocalProvider(/* … */) { // set LocalContentAlpha
            ProvideTextStyle(MaterialTheme.typography.button) {
                Row(
                    // …
                    content = content
                )
            }
        }
    }
}

৪টি কম্পোনেন্ট দিয়ে একটি Button তৈরি হয়:

  1. ব্যাকগ্রাউন্ড, আকার, ক্লিক হ্যান্ডেলিং ইত্যাদি প্রদানকারী মেটেরিয়াল Surface

  2. A CompositionLocalProvider বোতাম চালু বা বন্ধ করা হলে যা কন্টেন্টের আলফা পরিবর্তন করে

  3. A ProvideTextStyle ব্যবহার করার জন্য ডিফল্ট টেক্সট স্টাইল সেট করে

  4. Row বোতামের কন্টেন্টের জন্য ডিফল্ট লেআউট নীতি প্রদান করে

আমরা স্ট্রাকচার আরও স্পষ্ট করার জন্য কিছু প্যারামিটার ও কমেন্ট বাদ দিয়েছি, কিন্তু সম্পূর্ণ কম্পোনেন্টটি কোডের মাত্র ৪০টি লাইন নিয়ে গঠিত, কারণ এটি বোতামটি প্রয়োগ করার জন্য এই ৪টি কম্পোনেন্টকে একত্রিত করে। Button এর মতো কম্পোনেন্ট কোন প্যারামিটার এক্সপোজ করবে সেই ব্যাপারে মতামত দেয়, এর ফলে সাধারণ কাস্টমাইজেশন চালু করার সাথে সাথে প্যারামিটারের সংখ্যাও বেড়ে যায়, এর ফলে কম্পোনেন্ট ব্যবহার করা কঠিন হয়ে পড়ে। যেমন, মেটেরিয়াল কম্পোনেন্ট, মেটেরিয়াল ডিজাইন সিস্টেমে নির্দিষ্ট করা কাস্টমাইজেশন অফার করে, এর ফলে মেটেরিয়াল ডিজাইন নীতি অনুসরণ করা সহজ হয়।

তবে, আপনি যদি কোনও কম্পোনেন্টের প্যারামিটারের বাইরে কাস্টমাইজেশন করতে চান, তাহলে আপনি একটি লেভেল "ড্রপ ডাউন" করতে এবং একটি কম্পোনেন্ট ফর্ক করতে পারবেন। যেমন, Material Design নির্দিষ্ট করে যে বোতামের ব্যাকগ্রাউন্ডে সলিড রঙ থাকতে হবে। আপনার যদি গ্রেডিয়েন্ট ব্যাকগ্রাউন্ডের প্রয়োজন হয়, তাহলে এই বিকল্পটি Button প্যারামিটার দ্বারা কাজ করে না। এই ক্ষেত্রে, আপনি Material Button ইমপ্লিমেন্টেশনকে রেফারেন্স হিসেবে ব্যবহার করে নিজের কম্পোনেন্ট তৈরি করতে পারেন:

@Composable
fun GradientButton(
    // …
    background: List<Color>,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Row(
        // …
        modifier = modifier
            .clickable(onClick = {})
            .background(
                Brush.horizontalGradient(background)
            )
    ) {
        CompositionLocalProvider(/* … */) { // set material LocalContentAlpha
            ProvideTextStyle(MaterialTheme.typography.button) {
                content()
            }
        }
    }
}

উপরে দেখানো ইমপ্লিমেন্টেশন Material লেয়ার থেকে কম্পোনেন্ট ব্যবহার করা চালিয়ে যায়, যেমন Material-এর বর্তমান কন্টেন্ট আলফা ও বর্তমান টেক্সট স্টাইল সংক্রান্ত ধারণা। তবে, এটি মেটেরিয়াল Surface-এর জায়গায় একটি Row বসায় এবং পছন্দমতো চেহারা পেতে স্টাইল করে।

আপনি যদি Material কনসেপ্ট একেবারেই ব্যবহার করতে না চান, যেমন, নিজের জন্য কাস্টম ডিজাইন সিস্টেম তৈরি করা, তাহলে আপনি ফাউন্ডেশন লেয়ার কম্পোনেন্ট ব্যবহার করতে পারেন:

@Composable
fun BespokeButton(
    // …
    backgroundColor: Color,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Row(
        // …
        modifier = modifier
            .clickable(onClick = {})
            .background(backgroundColor)
    ) {
        // No Material components used
        content()
    }
}

Jetpack Compose সর্বোচ্চ লেভেলের কম্পোনেন্টগুলির জন্য সবচেয়ে সহজ নাম রিজার্ভ করে। যেমন, androidx.compose.material.Text এর উপর ভিত্তি করে androidx.compose.foundation.text.BasicText তৈরি করা হয়েছে। আপনি যদি উচ্চতর লেভেল রিপ্লেস করতে চান, তাহলে এটি আপনাকে সবচেয়ে বেশি খুঁজে পাওয়া যায় এমন নাম সহ নিজের ইমপ্লিমেন্টেশন প্রদান করতে সাহায্য করে।

সঠিক অ্যাবস্ট্রাকশন বেছে নেওয়া

লেয়ার করা, আবার ব্যবহারযোগ্য কম্পোনেন্ট তৈরি করার Compose-এর দর্শন অনুযায়ী, আপনাকে সবসময় লোয়ার লেভেল বিল্ডিং ব্লক ব্যবহার করতে হবে না। অনেক উচ্চ-স্তরের কম্পোনেন্ট শুধু আরও বেশি কার্যকারিতাই অফার করে না, তার সাথে অ্যাক্সেসিবিলিটি সাপোর্ট করার মতো সর্বোত্তম পদ্ধতিও প্রয়োগ করে।

যেমন, আপনি যদি নিজের কাস্টম কম্পোনেন্টে জেসচার সাপোর্ট যোগ করতে চান, তাহলে Modifier.pointerInput ব্যবহার করে এটি প্রথম থেকে তৈরি করতে পারেন তবে এর উপরে তৈরি করা অন্যান্য, আরও উন্নত কম্পোনেন্ট আছে যা আরও ভাল স্টার্টিং পয়েন্ট অফার করতে পারে, যেমন Modifier.draggable, Modifier.scrollable বা Modifier.swipeable.

সাধারণত, সর্বোচ্চ-লেভেলের কম্পোনেন্ট ব্যবহার করে তৈরি করা ভাল, কারণ এতে এমন কার্যকারিতা থাকে যা আপনাকে সেরা প্র্যাক্টিস থেকে উপকৃত হতে সাহায্য করে।

আরও জানুন

কাস্টম ডিজাইন সিস্টেম তৈরি করার উদাহরণ হিসেবে Jetsnack স্যাম্পেল দেখুন।