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

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

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

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

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

  • AppCompat লাইব্রেরি ব্যবহার করে মেটেরিয়াল ডিজাইন 1 (যেমন Theme.AppCompat.* )
  • MDC-Android লাইব্রেরি ব্যবহার করে ম্যাটেরিয়াল ডিজাইন 2 (যেমন Theme.MaterialComponents.* )
  • MDC-Android লাইব্রেরি ব্যবহার করে ম্যাটেরিয়াল ডিজাইন 3 (যেমন Theme.Material3.* )

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

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

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

সমস্ত জেটপ্যাক কম্পোজ নমুনা MaterialTheme উপরে তৈরি একটি কাস্টম কম্পোজ থিম ব্যবহার করে।

আরও জানতে কম্পোজ করার জন্য কম্পোজ এবং মাইগ্রেটিং XML থিমগুলিতে ডিজাইন সিস্টেমগুলি দেখুন৷

আপনি যদি আপনার অ্যাপে নেভিগেশন কম্পোনেন্ট ব্যবহার করেন, তাহলে আরও তথ্যের জন্য কম্পোজের সাথে নেভিগেটিং - ইন্টারঅপারেবিলিটি এবং জেটপ্যাক নেভিগেশনকে নেভিগেশন কম্পোজে মাইগ্রেট করুন দেখুন।

আপনার মিশ্র রচনা/ভিউ UI পরীক্ষা করুন

আপনার অ্যাপের অংশগুলি রচনায় স্থানান্তরিত করার পরে, আপনি কিছু ভাঙেননি তা নিশ্চিত করার জন্য পরীক্ষা করা গুরুত্বপূর্ণ৷

যখন কোনো কার্যকলাপ বা খণ্ড রচনা ব্যবহার করে, তখন আপনাকে ActivityScenarioRule ব্যবহার না করে createAndroidComposeRule ব্যবহার করতে হবে। createAndroidComposeRule একটি ComposeTestRule এর সাথে ActivityScenarioRule সংহত করে যা আপনাকে একই সময়ে কম্পোজ এবং ভিউ কোড পরীক্ষা করতে দেয়।

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

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

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

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

রচনায় একটি ViewModel ব্যবহার করা

আপনি যদি আর্কিটেকচার কম্পোনেন্টস ViewModel লাইব্রেরি ব্যবহার করেন, তাহলে আপনি viewModel() ফাংশনে কল করে যেকোন কম্পোজেবল থেকে একটি ViewModel অ্যাক্সেস করতে পারেন, যেমন Compose এবং অন্যান্য লাইব্রেরিতে ব্যাখ্যা করা হয়েছে।

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

উদাহরণস্বরূপ, যদি কম্পোজেবলগুলি একটি অ্যাক্টিভিটিতে হোস্ট করা হয়, তাহলে 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 এর একটি অংশে রচনা গ্রহণ করেন, তখন এটি সম্ভব যে রচনা এবং ভিউ সিস্টেম কোডের ডেটা ভাগ করতে হবে৷ যখন সম্ভব, আমরা আপনাকে সেই শেয়ার করা অবস্থাটিকে অন্য ক্লাসে এনক্যাপসুলেট করার পরামর্শ দিই যা উভয় প্ল্যাটফর্মের দ্বারা ব্যবহৃত UDF সেরা অনুশীলনগুলি অনুসরণ করে; উদাহরণস্বরূপ, একটি ViewModel এ যা ডেটা আপডেট নির্গত করার জন্য ভাগ করা ডেটার একটি স্ট্রিম প্রকাশ করে।

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

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

কম্পোজ স্টেটকে নন-কম্পোজ কোডে প্রকাশ করতে 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
}

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

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

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

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

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 স্থানান্তর করা হচ্ছে

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

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

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

@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 সাথেই আবদ্ধ থাকে।

বিপরীতে, কম্পোজ কোটলিনে শর্তসাপেক্ষ যুক্তি ব্যবহার করে সম্পূর্ণ ভিন্ন কম্পোজেবল প্রদর্শন করা সহজ করে তোলে:

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

ডিজাইন অনুসারে, CautionIcon কেন এটি প্রদর্শিত হচ্ছে তা জানার বা যত্ন নেওয়ার দরকার নেই এবং visibility কোনও ধারণা নেই: এটি হয় কম্পোজিশনে রয়েছে, বা এটি নেই৷

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

এনক্যাপসুলেটেড এবং পুনরায় ব্যবহারযোগ্য উপাদান প্রচার করুন

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

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

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

@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 তৈরি করতে কম্পোজ যে কৌশলগুলি অফার করে সে সম্পর্কে জানতে বিভিন্ন স্ক্রীনের আকার সমর্থন করুন

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

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

RecyclerView এ রচনা করুন

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

WindowInsets ভিউ এর সাথে ইন্টারপ করে

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

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

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

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

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

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

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

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

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

  • AppCompat লাইব্রেরি ব্যবহার করে মেটেরিয়াল ডিজাইন 1 (যেমন Theme.AppCompat.* )
  • MDC-Android লাইব্রেরি ব্যবহার করে ম্যাটেরিয়াল ডিজাইন 2 (যেমন Theme.MaterialComponents.* )
  • MDC-Android লাইব্রেরি ব্যবহার করে ম্যাটেরিয়াল ডিজাইন 3 (যেমন Theme.Material3.* )

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

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

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

সমস্ত জেটপ্যাক কম্পোজ নমুনা MaterialTheme উপরে তৈরি একটি কাস্টম কম্পোজ থিম ব্যবহার করে।

আরও জানতে কম্পোজ করার জন্য কম্পোজ এবং মাইগ্রেটিং XML থিমগুলিতে ডিজাইন সিস্টেমগুলি দেখুন৷

আপনি যদি আপনার অ্যাপে নেভিগেশন কম্পোনেন্ট ব্যবহার করেন, তাহলে আরও তথ্যের জন্য কম্পোজের সাথে নেভিগেটিং - ইন্টারঅপারেবিলিটি এবং জেটপ্যাক নেভিগেশনকে নেভিগেশন কম্পোজে মাইগ্রেট করুন দেখুন।

আপনার মিশ্র রচনা/ভিউ UI পরীক্ষা করুন

আপনার অ্যাপের অংশগুলি রচনায় স্থানান্তরিত করার পরে, আপনি কিছু ভাঙেননি তা নিশ্চিত করার জন্য পরীক্ষা করা গুরুত্বপূর্ণ৷

যখন কোনো কার্যকলাপ বা খণ্ড রচনা ব্যবহার করে, তখন আপনাকে ActivityScenarioRule ব্যবহার না করে createAndroidComposeRule ব্যবহার করতে হবে। createAndroidComposeRule একটি ComposeTestRule এর সাথে ActivityScenarioRule সংহত করে যা আপনাকে একই সময়ে কম্পোজ এবং ভিউ কোড পরীক্ষা করতে দেয়।

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

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

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

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

রচনায় একটি ViewModel ব্যবহার করা

আপনি যদি আর্কিটেকচার কম্পোনেন্টস ViewModel লাইব্রেরি ব্যবহার করেন, তাহলে আপনি viewModel() ফাংশনে কল করে যেকোন কম্পোজেবল থেকে একটি ViewModel অ্যাক্সেস করতে পারেন, যেমন Compose এবং অন্যান্য লাইব্রেরিতে ব্যাখ্যা করা হয়েছে।

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

উদাহরণস্বরূপ, যদি কম্পোজেবলগুলি একটি অ্যাক্টিভিটিতে হোস্ট করা হয়, তাহলে 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 এর একটি অংশে রচনা গ্রহণ করেন, তখন এটি সম্ভব যে রচনা এবং ভিউ সিস্টেম কোডের ডেটা ভাগ করতে হবে৷ যখন সম্ভব, আমরা আপনাকে সেই শেয়ার করা অবস্থাটিকে অন্য ক্লাসে এনক্যাপসুলেট করার পরামর্শ দিই যা উভয় প্ল্যাটফর্মের দ্বারা ব্যবহৃত UDF সেরা অনুশীলনগুলি অনুসরণ করে; উদাহরণস্বরূপ, একটি ViewModel এ যা ডেটা আপডেট নির্গত করার জন্য ভাগ করা ডেটার একটি স্ট্রিম প্রকাশ করে।

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

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

কম্পোজ স্টেটকে নন-কম্পোজ কোডে প্রকাশ করতে 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
}

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

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

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

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

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 স্থানান্তর করা হচ্ছে

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

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

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

@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 সাথেই আবদ্ধ থাকে।

বিপরীতে, কম্পোজ কোটলিনে শর্তসাপেক্ষ যুক্তি ব্যবহার করে সম্পূর্ণ ভিন্ন কম্পোজেবল প্রদর্শন করা সহজ করে তোলে:

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

ডিজাইন অনুসারে, CautionIcon কেন এটি প্রদর্শিত হচ্ছে তা জানার বা যত্ন নেওয়ার দরকার নেই এবং visibility কোনও ধারণা নেই: এটি হয় কম্পোজিশনে রয়েছে, বা এটি নেই৷

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

এনক্যাপসুলেটেড এবং পুনরায় ব্যবহারযোগ্য উপাদান প্রচার করুন

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

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

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

@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 তৈরি করতে কম্পোজ যে কৌশলগুলি অফার করে সে সম্পর্কে জানতে বিভিন্ন স্ক্রীনের আকার সমর্থন করুন

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

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

RecyclerView এ রচনা করুন

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

WindowInsets ভিউ এর সাথে ইন্টারপ করে

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

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

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

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

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