অন্যান্য বিবেচ্য বিষয়

ভিউ থেকে কম্পোজে মাইগ্রেট করা সম্পূর্ণরূপে UI-সম্পর্কিত হলেও, একটি নিরাপদ এবং পর্যায়ক্রমিক মাইগ্রেশন সম্পন্ন করার জন্য অনেক বিষয় বিবেচনা করতে হয়। এই পৃষ্ঠায় আপনার ভিউ-ভিত্তিক অ্যাপকে কম্পোজে মাইগ্রেট করার সময় বিবেচ্য কিছু বিষয় উল্লেখ করা হয়েছে।

আপনার অ্যাপের থিম স্থানান্তর করা হচ্ছে

অ্যান্ড্রয়েড অ্যাপের থিমিংয়ের জন্য ম্যাটেরিয়াল ডিজাইন হলো প্রস্তাবিত ডিজাইন সিস্টেম।

ভিউ-ভিত্তিক অ্যাপের জন্য ম্যাটেরিয়ালের তিনটি সংস্করণ উপলব্ধ রয়েছে:

  • AppCompat লাইব্রেরি (অর্থাৎ Theme.AppCompat.* ) ব্যবহার করে ম্যাটেরিয়াল ডিজাইন ১
  • MDC-Android লাইব্রেরি ব্যবহার করে ম্যাটেরিয়াল ডিজাইন ২ (অর্থাৎ Theme.MaterialComponents.* )
  • MDC-Android লাইব্রেরি ব্যবহার করে ম্যাটেরিয়াল ডিজাইন ৩ (অর্থাৎ Theme.Material3.* )

কম্পোজ অ্যাপের জন্য ম্যাটেরিয়ালের দুটি সংস্করণ উপলব্ধ রয়েছে:

  • কম্পোজ ম্যাটেরিয়াল লাইব্রেরি (অর্থাৎ androidx.compose.material.MaterialTheme ) ব্যবহার করে ম্যাটেরিয়াল ডিজাইন ২
  • Compose Material 3 লাইব্রেরি (অর্থাৎ androidx.compose.material3.MaterialTheme ) ব্যবহার করে Material Design 3

আপনার অ্যাপের ডিজাইন সিস্টেম সক্ষম হলে, আমরা সর্বশেষ সংস্করণ (মেটেরিয়াল ৩) ব্যবহার করার পরামর্শ দিই। ভিউ এবং কম্পোজ উভয়ের জন্যই মাইগ্রেশন গাইড উপলব্ধ আছে:

কম্পোজে নতুন স্ক্রিন তৈরি করার সময়, আপনি ম্যাটেরিয়াল ডিজাইনের যে সংস্করণই ব্যবহার করুন না কেন, কম্পোজ ম্যাটেরিয়াল লাইব্রেরি থেকে UI নির্গত করে এমন যেকোনো কম্পোজেবলের আগে একটি MaterialTheme প্রয়োগ করা নিশ্চিত করুন। ম্যাটেরিয়াল কম্পোনেন্টগুলো ( Button , Text , ইত্যাদি) একটি MaterialTheme উপস্থিতির উপর নির্ভরশীল এবং এটি ছাড়া তাদের আচরণ অনির্ধারিত থাকে।

সমস্ত Jetpack Compose স্যাম্পলে MaterialTheme এর উপর ভিত্তি করে নির্মিত একটি কাস্টম Compose থিম ব্যবহার করা হয়।

আরও জানতে Compose-এ ডিজাইন সিস্টেম এবং Compose-এ XML থিম মাইগ্রেট করা দেখুন।

আপনি যদি আপনার অ্যাপে নেভিগেশন কম্পোনেন্ট ব্যবহার করেন, তাহলে আরও তথ্যের জন্য ‘ Navigating with Compose - Interoperability’ এবং ‘Migrate Jetpack Navigation to Navigation Compose’ দেখুন।

আপনার মিশ্র Compose/Views UI পরীক্ষা করুন

আপনার অ্যাপের কিছু অংশ Compose-এ স্থানান্তরিত করার পর, কোনো কিছু নষ্ট হয়ে যায়নি তা নিশ্চিত করার জন্য টেস্টিং করা অত্যন্ত জরুরি।

যখন কোনো অ্যাক্টিভিটি বা ফ্র্যাগমেন্ট Compose ব্যবহার করে, তখন ActivityScenarioRule পরিবর্তে createAndroidComposeRule ব্যবহার করতে হবে। createAndroidComposeRule ActivityScenarioRule এর সাথে একটি ComposeTestRule একীভূত করে, যা আপনাকে একই সাথে Compose এবং View কোড পরীক্ষা করার সুযোগ দেয়।

class MyActivityTest {
    @Rule
    @JvmField
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test
    fun testGreeting() {
        val greeting = InstrumentationRegistry.getInstrumentation()
            .targetContext.resources.getString(R.string.greeting)

        composeTestRule.onNodeWithText(greeting).assertIsDisplayed()
    }
}

টেস্টিং সম্পর্কে আরও জানতে আপনার Compose লেআউট টেস্টিং দেখুন। UI টেস্টিং ফ্রেমওয়ার্কগুলির সাথে আন্তঃকার্যক্ষমতার জন্য, Espresso-এর সাথে আন্তঃকার্যক্ষমতা এবং UiAutomator-এর সাথে আন্তঃকার্যক্ষমতা দেখুন।

আপনার বিদ্যমান অ্যাপ আর্কিটেকচারের সাথে কম্পোজকে একীভূত করা

ইউনিডিরেকশনাল ডেটা ফ্লো (UDF) আর্কিটেকচার প্যাটার্ন কম্পোজের সাথে নির্বিঘ্নে কাজ করে। যদি অ্যাপটি এর পরিবর্তে মডেল ভিউ প্রেজেন্টার (MVP)-এর মতো অন্য ধরনের আর্কিটেকচার প্যাটার্ন ব্যবহার করে, তাহলে আমরা আপনাকে কম্পোজ গ্রহণ করার আগে বা গ্রহণ করার সময় UI-এর সেই অংশটি UDF-এ মাইগ্রেট করার পরামর্শ দিই।

কম্পোজে একটি ViewModel ব্যবহার করা

আপনি যদি Architecture Components-এর ViewModel লাইব্রেরি ব্যবহার করেন, তাহলে Compose and other libraries অংশে ব্যাখ্যা করা পদ্ধতি অনুযায়ী viewModel() ফাংশনটি কল করে যেকোনো কম্পোজেবল থেকে একটি ViewModel অ্যাক্সেস করতে পারবেন।

Compose ব্যবহার করার সময়, বিভিন্ন কম্পোজেবলে একই ViewModel টাইপ ব্যবহার করার ব্যাপারে সতর্ক থাকুন, কারণ ViewModel এলিমেন্টগুলো ভিউ-লাইফসাইকেল স্কোপ অনুসরণ করে। স্কোপটি হবে হোস্ট অ্যাক্টিভিটি, ফ্র্যাগমেন্ট, অথবা নেভিগেশন লাইব্রেরি ব্যবহার করা হলে নেভিগেশন গ্রাফ।

উদাহরণস্বরূপ, যদি কম্পোজেবলগুলো কোনো অ্যাক্টিভিটিতে হোস্ট করা হয়, তাহলে viewModel() সবসময় একই ইনস্ট্যান্স রিটার্ন করে, যা শুধুমাত্র অ্যাক্টিভিটি শেষ হলেই ক্লিয়ার হয়। নিচের উদাহরণে, একই ব্যবহারকারীকে ("user1") দুইবার সম্ভাষণ জানানো হয়েছে, কারণ হোস্ট অ্যাক্টিভিটির অধীনে থাকা সমস্ত কম্পোজেবলে একই GreetingViewModel ইনস্ট্যান্সটি পুনঃব্যবহৃত হয়েছে। প্রথম তৈরি হওয়া ViewModel ইনস্ট্যান্সটি অন্যান্য কম্পোজেবলে পুনঃব্যবহৃত হয়।

class GreetingActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            MaterialTheme {
                Column {
                    GreetingScreen("user1")
                    GreetingScreen("user2")
                }
            }
        }
    }
}

@Composable
fun GreetingScreen(
    userId: String,
    viewModel: GreetingViewModel = viewModel(  
        factory = GreetingViewModelFactory(userId)  
    )
) {
    val messageUser by viewModel.message.observeAsState("")
    Text(messageUser)
}

class GreetingViewModel(private val userId: String) : ViewModel() {
    private val _message = MutableLiveData("Hi $userId")
    val message: LiveData<String> = _message
}

class GreetingViewModelFactory(private val userId: String) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return GreetingViewModel(userId) as T
    }
}

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

@Composable
fun MyApp() {
    NavHost(rememberNavController(), startDestination = "profile/{userId}") {
        /* ... */
        composable("profile/{userId}") { backStackEntry ->
            GreetingScreen(backStackEntry.arguments?.getString("userId") ?: "")
        }
    }
}

সত্যের উৎস উল্লেখ করুন

যখন আপনি UI-এর কোনো একটি অংশে Compose ব্যবহার করেন, তখন Compose এবং View সিস্টেম কোডের মধ্যে ডেটা আদান-প্রদানের প্রয়োজন হতে পারে। সম্ভব হলে, আমরা আপনাকে সেই শেয়ার করা স্টেটটিকে এমন একটি ক্লাসের মধ্যে এনক্যাপসুলেট করার পরামর্শ দিই, যা উভয় প্ল্যাটফর্মে ব্যবহৃত UDF-এর সেরা অনুশীলনগুলো অনুসরণ করে; উদাহরণস্বরূপ, এমন একটি ViewModel এ, যা ডেটা আপডেট নির্গত করার জন্য শেয়ার করা ডেটার একটি স্ট্রিম প্রকাশ করে।

তবে, যদি শেয়ার করার ডেটা পরিবর্তনযোগ্য হয় বা কোনো UI এলিমেন্টের সাথে দৃঢ়ভাবে আবদ্ধ থাকে, তাহলে এটি সবসময় সম্ভব হয় না। সেক্ষেত্রে, একটি সিস্টেমকে তথ্যের মূল উৎস হতে হবে এবং সেই সিস্টেমকে অন্য সিস্টেমের সাথে যেকোনো ডেটা আপডেট শেয়ার করতে হবে। একটি সাধারণ নিয়ম হিসেবে, UI হায়ারার্কির মূলের (root) সবচেয়ে কাছের এলিমেন্টটিরই তথ্যের মূল উৎস হওয়া উচিত।

সত্যের উৎস হিসেবে রচনা করুন

নন-কম্পোজ কোডে কম্পোজ স্টেট প্রকাশ করতে SideEffect কম্পোজেবল ব্যবহার করুন। এক্ষেত্রে, তথ্যের মূল উৎস একটি কম্পোজেবলের মধ্যে রাখা হয়, যা স্টেটের আপডেট পাঠায়।

উদাহরণস্বরূপ, আপনার অ্যানালিটিক্স লাইব্রেরি আপনাকে পরবর্তী সমস্ত অ্যানালিটিক্স ইভেন্টের সাথে কাস্টম মেটাডেটা (এই উদাহরণে ব্যবহারকারীর বৈশিষ্ট্য ) সংযুক্ত করে আপনার ব্যবহারকারী গোষ্ঠীকে বিভক্ত করার সুযোগ দিতে পারে। বর্তমান ব্যবহারকারীর ধরন আপনার অ্যানালিটিক্স লাইব্রেরিকে জানাতে, এর মান আপডেট করার জন্য SideEffect ব্যবহার করুন।

@Composable
fun rememberFirebaseAnalytics(user: User): FirebaseAnalytics {
    val analytics: FirebaseAnalytics = remember {
        FirebaseAnalytics()
    }

    // On every successful composition, update FirebaseAnalytics with
    // the userType from the current User, ensuring that future analytics
    // events have this metadata attached
    SideEffect {
        analytics.setUserProperty("userType", user.userType)
    }
    return analytics
}

আরও তথ্যের জন্য, Compose-এর পার্শ্ব-প্রতিক্রিয়া দেখুন।

সিস্টেমকে সত্যের উৎস হিসেবে দেখুন

যদি ভিউ সিস্টেম স্টেটের মালিক হয় এবং তা কম্পোজের সাথে শেয়ার করে, তাহলে আমরা সুপারিশ করি যে আপনি স্টেটটিকে mutableStateOf ) অবজেক্টের মধ্যে র‍্যাপ করুন, যাতে এটি কম্পোজের জন্য থ্রেড-সেফ হয়। আপনি যদি এই পদ্ধতি ব্যবহার করেন, তাহলে কম্পোজেবল ফাংশনগুলো সরলীকৃত হয়, কারণ সেগুলোর কাছে আর তথ্যের মূল উৎস থাকে না, কিন্তু ভিউ সিস্টেমকে মিউটেবল স্টেট এবং সেই স্টেট ব্যবহারকারী ভিউগুলোকে আপডেট করতে হয়।

নিচের উদাহরণে, একটি CustomViewGroup একটি TextView এবং একটি ComposeView রয়েছে, যার ভেতরে একটি কম্পোজেবল TextField আছে। ব্যবহারকারী TextField এ যা টাইপ করবে, সেই বিষয়বস্তু TextView টিতে প্রদর্শন করতে হবে।

class CustomViewGroup @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : LinearLayout(context, attrs, defStyle) {

    // Source of truth in the View system as mutableStateOf
    // to make it thread-safe for Compose
    private var text by mutableStateOf("")

    private val textView: TextView

    init {
        orientation = VERTICAL

        textView = TextView(context)
        val composeView = ComposeView(context).apply {
            setContent {
                MaterialTheme {
                    TextField(value = text, onValueChange = { updateState(it) })
                }
            }
        }

        addView(textView)
        addView(composeView)
    }

    // Update both the source of truth and the TextView
    private fun updateState(newValue: String) {
        text = newValue
        textView.text = newValue
    }
}

শেয়ার্ড UI স্থানান্তর করা হচ্ছে

আপনি যদি পর্যায়ক্রমে Compose-এ স্থানান্তরিত হন, তাহলে আপনার Compose এবং View সিস্টেম উভয় ক্ষেত্রেই শেয়ার করা UI এলিমেন্ট ব্যবহার করার প্রয়োজন হতে পারে। উদাহরণস্বরূপ, যদি আপনার অ্যাপে একটি কাস্টম CallToActionButton কম্পোনেন্ট থাকে, তাহলে আপনাকে এটি Compose এবং View-ভিত্তিক স্ক্রিন উভয় ক্ষেত্রেই ব্যবহার করতে হতে পারে।

Compose-এ, শেয়ার করা UI এলিমেন্টগুলো কম্পোজেবল-এ পরিণত হয়, যা অ্যাপ জুড়ে পুনরায় ব্যবহার করা যায়; এলিমেন্টটি XML দিয়ে স্টাইল করা হোক বা কাস্টম ভিউ হোক, তা নির্বিশেষে। উদাহরণস্বরূপ, আপনি আপনার কাস্টম কল টু অ্যাকশন Button কম্পোনেন্টের জন্য একটি CallToActionButton কম্পোজেবল তৈরি করবেন।

ভিউ-ভিত্তিক স্ক্রিনে কম্পোজেবল ব্যবহার করতে, AbstractComposeView থেকে এক্সটেন্ড করে একটি কাস্টম ভিউ র‍্যাপার তৈরি করুন। এর ওভাররাইড করা Content কম্পোজেবলের মধ্যে, আপনার তৈরি করা কম্পোজেবলটিকে আপনার Compose থিমে র‍্যাপ করে রাখুন, যেমনটি নিচের উদাহরণে দেখানো হয়েছে:

@Composable
fun CallToActionButton(
    text: String,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
) {
    Button(
        colors = ButtonDefaults.buttonColors(
            containerColor = MaterialTheme.colorScheme.secondary
        ),
        onClick = onClick,
        modifier = modifier,
    ) {
        Text(text)
    }
}

class CallToActionViewButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : AbstractComposeView(context, attrs, defStyle) {

    var text by mutableStateOf("")
    var onClick by mutableStateOf({})

    @Composable
    override fun Content() {
        YourAppTheme {
            CallToActionButton(text, onClick)
        }
    }
}

লক্ষ্য করুন যে, কম্পোজেবল প্যারামিটারগুলো কাস্টম ভিউয়ের ভেতরে মিউটেবল ভেরিয়েবলে পরিণত হয়। এর ফলে কাস্টম CallToActionViewButton ভিউটি একটি প্রচলিত ভিউয়ের মতো ইনফ্লেটেবল ও ব্যবহারযোগ্য হয়ে ওঠে। নিচে ভিউ বাইন্ডিং ব্যবহার করে এর একটি উদাহরণ দেখুন:

class ViewBindingActivity : ComponentActivity() {

    private lateinit var binding: ActivityExampleBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityExampleBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.callToAction.apply {
            text = getString(R.string.greeting)
            onClick = { /* Do something */ }
        }
    }
}

কাস্টম কম্পোনেন্টটিতে যদি পরিবর্তনযোগ্য স্টেট থাকে, তাহলে স্টেটের নির্ভরযোগ্য উৎস দেখুন।

প্রেজেন্টেশন থেকে স্টেট আলাদা করাকে অগ্রাধিকার দিন

ঐতিহ্যগতভাবে, একটি View স্টেটফুল হয়। একটি View কী প্রদর্শন করতে হবে এবং কীভাবে তা প্রদর্শন করতে হবে, তা বর্ণনা করে এমন ফিল্ডগুলো পরিচালনা করে। যখন আপনি একটি View কম্পোজে রূপান্তর করেন, তখন একমুখী ডেটা প্রবাহ অর্জনের জন্য রেন্ডার করা ডেটা আলাদা করার চেষ্টা করুন, যেমনটি স্টেট হোস্টিং- এ আরও ব্যাখ্যা করা হয়েছে।

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

এর বিপরীতে, Kotlin-এ Compose কন্ডিশনাল লজিক ব্যবহার করে সম্পূর্ণ ভিন্ন কম্পোজেবল প্রদর্শন করা সহজ করে তোলে:

@Composable
fun MyComposable(showCautionIcon: Boolean) {
    if (showCautionIcon) {
        CautionIcon(/* ... */)
    }
}

এর গঠন অনুযায়ী, CautionIcon কেন দেখানো হচ্ছে তা জানার বা বিবেচনা করার কোনো প্রয়োজন নেই, এবং এর visibility কোনো ধারণাও নেই: এটি হয় Composition-এ থাকে, অথবা থাকে না।

স্টেট ম্যানেজমেন্ট এবং প্রেজেন্টেশন লজিককে সুস্পষ্টভাবে আলাদা করার মাধ্যমে, আপনি স্টেটকে UI-তে রূপান্তর করার সময় কন্টেন্ট প্রদর্শনের পদ্ধতি আরও স্বাধীনভাবে পরিবর্তন করতে পারেন। প্রয়োজনে স্টেটকে হোইস্ট করার ক্ষমতা কম্পোজেবলগুলোকে আরও পুনঃব্যবহারযোগ্য করে তোলে, কারণ এতে স্টেটের মালিকানা আরও নমনীয় হয়।

আবদ্ধ এবং পুনঃব্যবহারযোগ্য উপাদান প্রচার করুন

View এলিমেন্টগুলো প্রায়শই জানে যে তারা কোথায় থাকে: একটি Activity , একটি Dialog , একটি Fragment বা অন্য কোনো View হায়ারার্কির মধ্যে। যেহেতু এগুলো প্রায়শই স্ট্যাটিক লেআউট ফাইল থেকে তৈরি হয়, তাই একটি View এর সামগ্রিক কাঠামো খুব অনমনীয় হয়ে থাকে। এর ফলে টাইট কাপলিং তৈরি হয় এবং একটি View পরিবর্তন বা পুনঃব্যবহার করা কঠিন হয়ে পড়ে।

উদাহরণস্বরূপ, একটি কাস্টম View ধরে নিতে পারে যে একটি নির্দিষ্ট আইডি সহ একটি নির্দিষ্ট ধরণের চাইল্ড ভিউ তার আছে, এবং কোনো একটি অ্যাকশনের প্রতিক্রিয়ায় সরাসরি তার প্রোপার্টিগুলো পরিবর্তন করে। এটি ঐ View এলিমেন্টগুলোকে একে অপরের সাথে দৃঢ়ভাবে সংযুক্ত করে: কাস্টম View চাইল্ডটিকে খুঁজে না পেলে ক্র্যাশ করতে পারে বা ভেঙে যেতে পারে, এবং কাস্টম View প্যারেন্ট ছাড়া চাইল্ডটিকেও সম্ভবত পুনরায় ব্যবহার করা যাবে না।

পুনরায় ব্যবহারযোগ্য কম্পোজেবল থাকলে Compose-এ এই সমস্যাটি কম হয়। প্যারেন্টরা সহজেই স্টেট এবং কলব্যাক নির্দিষ্ট করে দিতে পারে, ফলে সেগুলো ঠিক কোথায় ব্যবহৃত হবে তা না জেনেই আপনি পুনরায় ব্যবহারযোগ্য কম্পোজেবল লিখতে পারেন।

@Composable
fun AScreen() {
    var isEnabled by rememberSaveable { mutableStateOf(false) }

    Column {
        ImageWithEnabledOverlay(isEnabled)
        ControlPanelWithToggle(
            isEnabled = isEnabled,
            onEnabledChanged = { isEnabled = it }
        )
    }
}

উপরের উদাহরণে, তিনটি অংশই আরও বেশি আবদ্ধ এবং কম সংযুক্ত:

  • ImageWithEnabledOverlay শুধু বর্তমান isEnabled অবস্থাটি জানলেই চলে। ControlPanelWithToggle অস্তিত্ব আছে কি না, বা এমনকি এটি কীভাবে নিয়ন্ত্রণযোগ্য, তা জানার কোনো প্রয়োজন এর নেই।

  • ControlPanelWithToggle জানে না যে ImageWithEnabledOverlay অস্তিত্ব আছে। isEnabled প্রদর্শিত হওয়ার শূন্য, এক বা একাধিক উপায় থাকতে পারে, এবং ControlPanelWithToggle পরিবর্তন করতে হবে না।

  • প্যারেন্টের কাছে ImageWithEnabledOverlay বা ControlPanelWithToggle কতটা গভীরে নেস্টেড আছে তা কোনো ব্যাপার না। ওই চাইল্ডগুলো পরিবর্তন অ্যানিমেট করতে, কন্টেন্ট অদলবদল করতে, অথবা অন্য চাইল্ডের কাছে কন্টেন্ট পাঠাতে পারে।

এই প্যাটার্নটি ইনভার্সন অফ কন্ট্রোল নামে পরিচিত, যা সম্পর্কে আপনি CompositionLocal ডকুমেন্টেশনে আরও পড়তে পারেন।

স্ক্রিনের আকার পরিবর্তন পরিচালনা করা

বিভিন্ন উইন্ডো সাইজের জন্য ভিন্ন ভিন্ন রিসোর্স থাকা রেসপন্সিভ View লেআউট তৈরির অন্যতম প্রধান উপায়। যদিও স্ক্রিন-লেভেল লেআউট সিদ্ধান্তের জন্য কোয়ালিফাইড রিসোর্স এখনও একটি বিকল্প, কম্পোজ সাধারণ কন্ডিশনাল লজিক ব্যবহার করে কোডের মাধ্যমে লেআউট সম্পূর্ণরূপে পরিবর্তন করা অনেক সহজ করে তোলে। আরও জানতে 'উইন্ডো সাইজ ক্লাসের ব্যবহার' দেখুন।

এছাড়াও, অ্যাডাপ্টিভ UI তৈরির জন্য Compose যে কৌশলগুলো প্রদান করে, সে সম্পর্কে জানতে “Support different display sizes” অংশটি দেখুন।

ভিউ সহ নেস্টেড স্ক্রোলিং

স্ক্রোলযোগ্য ভিউ এলিমেন্ট এবং স্ক্রোলযোগ্য কম্পোজেবলগুলির মধ্যে উভয় দিকে নেস্টেড স্ক্রোলিং ইন্টারোপ কীভাবে সক্ষম করা যায় সে সম্পর্কে আরও তথ্যের জন্য, "নেস্টেড স্ক্রোলিং ইন্টারোপ" পড়ুন।

RecyclerView তে রচনা করুন

RecyclerView সংস্করণ 1.3.0-alpha02 থেকে এর কম্পোজেবলগুলো উন্নত পারফরম্যান্স প্রদান করে। এই সুবিধাগুলো পেতে RecyclerView নিশ্চিত করুন যে আপনি RecyclerView এর অন্তত 1.3.0-alpha02 সংস্করণটি ব্যবহার করছেন।

WindowInsets View-গুলির সাথে ইন্টারঅ্যাক্ট করে

আপনার স্ক্রিনে একই হায়ারার্কিতে ভিউ এবং কম্পোজ কোড উভয়ই থাকলে ডিফল্ট ইনসেটগুলো ওভাররাইড করার প্রয়োজন হতে পারে। এক্ষেত্রে, কোনটি ইনসেটগুলো গ্রহণ করবে এবং কোনটি তা উপেক্ষা করবে, সে বিষয়ে আপনাকে সুস্পষ্টভাবে উল্লেখ করতে হবে।

উদাহরণস্বরূপ, যদি আপনার সবচেয়ে বাইরের লেআউটটি একটি অ্যান্ড্রয়েড ভিউ লেআউট হয়, তাহলে আপনার ভিউ সিস্টেমে ইনসেটগুলি ব্যবহার করা উচিত এবং কম্পোজের জন্য সেগুলিকে উপেক্ষা করা উচিত। বিকল্পভাবে, যদি আপনার সবচেয়ে বাইরের লেআউটটি একটি কম্পোজেবল হয়, তাহলে আপনার কম্পোজে ইনসেটগুলি ব্যবহার করা উচিত এবং সেই অনুযায়ী AndroidView কম্পোজেবলগুলিকে প্যাড করা উচিত।

ডিফল্টরূপে, প্রতিটি ComposeView সমস্ত ইনসেটকে WindowInsetsCompat কনজাম্পশন লেভেলে ব্যবহার করে। এই ডিফল্ট আচরণ পরিবর্তন করতে, ComposeView.consumeWindowInsets false এ সেট করুন।

আরও তথ্যের জন্য, Compose ডকুমেন্টেশনে WindowInsets পড়ুন।

{% হুবহু %} {% endverbatim %} {% হুবহু %} {% endverbatim %}