Modifier.clickable ব্যবহার করে এমন ইন্টারেক্টিভ কম্পোনেন্টগুলির কম্পোজিশন কর্মক্ষমতা উন্নত করতে, আমরা নতুন API চালু করেছি। এই APIগুলি আরও দক্ষ Indication বাস্তবায়নের অনুমতি দেয়, যেমন রিপলস।
androidx.compose.foundation:foundation:1.7.0+ এবং androidx.compose.material:material-ripple:1.7.0+ নিম্নলিখিত API পরিবর্তনগুলি অন্তর্ভুক্ত করে:
অবচয় | প্রতিস্থাপন |
|---|---|
| |
| এর পরিবর্তে মেটেরিয়াল লাইব্রেরিতে দেওয়া নতুন দ্রষ্টব্য: এই প্রসঙ্গে, "মেটেরিয়াল লাইব্রেরি" বলতে |
| হয়:
|
এই পৃষ্ঠাটি আচরণ পরিবর্তনের প্রভাব এবং নতুন API-এ স্থানান্তরিত করার নির্দেশাবলী বর্ণনা করে।
আচরণ পরিবর্তন
নিম্নলিখিত লাইব্রেরি সংস্করণগুলির মধ্যে একটি লহরী আচরণ পরিবর্তন অন্তর্ভুক্ত:
-
androidx.compose.material:material:1.7.0+ -
androidx.compose.material3:material3:1.3.0+ -
androidx.wear.compose:compose-material:1.4.0+
ম্যাটেরিয়াল লাইব্রেরিগুলির এই সংস্করণগুলি আর rememberRipple() ব্যবহার করে না; পরিবর্তে, তারা নতুন রিপল API ব্যবহার করে। ফলস্বরূপ, তারা LocalRippleTheme জিজ্ঞাসা করে না। অতএব, আপনি যদি আপনার অ্যাপ্লিকেশনে LocalRippleTheme সেট করেন, উপাদান উপাদানগুলি এই মানগুলি ব্যবহার করবে না ।
নিম্নলিখিত বিভাগগুলি বর্ণনা করে যে কীভাবে নতুন API-এ স্থানান্তর করা যায়।
ripple থেকে rememberRipple মাইগ্রেট করুন
একটি উপাদান লাইব্রেরি ব্যবহার করে
আপনি যদি একটি ম্যাটেরিয়াল লাইব্রেরি ব্যবহার করেন, তাহলে সংশ্লিষ্ট লাইব্রেরি থেকে ripple() কে কল করার সাথে rememberRipple() সরাসরি প্রতিস্থাপন করুন। এই API উপাদান থিম API থেকে প্রাপ্ত মান ব্যবহার করে একটি লহর তৈরি করে। তারপরে, ফিরে আসা বস্তুটিকে Modifier.clickable এবং/অথবা অন্যান্য উপাদানে পাস করুন।
উদাহরণস্বরূপ, নিম্নোক্ত স্নিপেট অবনমিত API ব্যবহার করে:
Box( Modifier.clickable( onClick = {}, interactionSource = remember { MutableInteractionSource() }, indication = rememberRipple() ) ) { // ... }
আপনার উপরের স্নিপেটটি এতে সংশোধন করা উচিত:
@Composable private fun RippleExample() { Box( Modifier.clickable( onClick = {}, interactionSource = remember { MutableInteractionSource() }, indication = ripple() ) ) { // ... } }
মনে রাখবেন যে ripple() আর একটি সংমিশ্রণযোগ্য ফাংশন নয় এবং মনে রাখার প্রয়োজন নেই। এটি মডিফায়ারের মতো একাধিক উপাদান জুড়েও পুনরায় ব্যবহার করা যেতে পারে, তাই বরাদ্দ সংরক্ষণ করতে রিপল তৈরিকে একটি শীর্ষ-স্তরের মান থেকে বের করার কথা বিবেচনা করুন।
কাস্টম ডিজাইন সিস্টেম বাস্তবায়ন
আপনি যদি আপনার নিজস্ব ডিজাইন সিস্টেম বাস্তবায়ন করেন, এবং আপনি রিপল কনফিগার করার জন্য একটি কাস্টম RippleTheme সাথে rememberRipple() ব্যবহার করে থাকেন, তাহলে আপনার নিজের রিপল API প্রদান করা উচিত যা material-ripple উন্মোচিত রিপল নোড এপিআই-কে প্রতিনিধিত্ব করে। তারপর, আপনার উপাদানগুলি আপনার নিজস্ব লহর ব্যবহার করতে পারে যা সরাসরি আপনার থিমের মানগুলিকে গ্রাস করে। আরও তথ্যের জন্য, RippleTheme থেকে মাইগ্রেট দেখুন।
RippleTheme থেকে মাইগ্রেট করুন
একটি প্রদত্ত উপাদানের জন্য একটি লহর নিষ্ক্রিয় করতে RippleTheme ব্যবহার করে৷
material এবং material3 লাইব্রেরিগুলি RippleConfiguration এবং LocalRippleConfiguration প্রকাশ করে, যা আপনাকে একটি সাবট্রির মধ্যে তরঙ্গের উপস্থিতি কনফিগার করতে দেয়। নোট করুন যে RippleConfiguration এবং LocalRippleConfiguration পরীক্ষামূলক, এবং শুধুমাত্র প্রতি-কম্পোনেন্ট কাস্টমাইজেশনের উদ্দেশ্যে। গ্লোবাল/থিম-ওয়াইড কাস্টমাইজেশন এই APIগুলির সাথে সমর্থিত নয়; সেই ব্যবহারের ক্ষেত্রে আরও তথ্যের জন্য একটি অ্যাপ্লিকেশনের সমস্ত লহরকে বিশ্বব্যাপী পরিবর্তন করতে RippleTheme ব্যবহার করা দেখুন।
উদাহরণস্বরূপ, নিম্নোক্ত স্নিপেট অবনমিত API ব্যবহার করে:
private object DisabledRippleTheme : RippleTheme { @Composable override fun defaultColor(): Color = Color.Transparent @Composable override fun rippleAlpha(): RippleAlpha = RippleAlpha(0f, 0f, 0f, 0f) } // ... CompositionLocalProvider(LocalRippleTheme provides DisabledRippleTheme) { Button { // ... } }
আপনার উপরের স্নিপেটটি এতে সংশোধন করা উচিত:
CompositionLocalProvider(LocalRippleConfiguration provides null) { Button { // ... } }
একটি প্রদত্ত উপাদানের জন্য একটি লহরের রঙ/আলফা পরিবর্তন করতে RippleTheme ব্যবহার করে
পূর্ববর্তী বিভাগে বর্ণিত হিসাবে, RippleConfiguration এবং LocalRippleConfiguration হল পরীক্ষামূলক API এবং শুধুমাত্র প্রতি-কম্পোনেন্ট কাস্টমাইজেশনের উদ্দেশ্যে।
উদাহরণস্বরূপ, নিম্নোক্ত স্নিপেট অবনমিত API ব্যবহার করে:
private object DisabledRippleThemeColorAndAlpha : RippleTheme { @Composable override fun defaultColor(): Color = Color.Red @Composable override fun rippleAlpha(): RippleAlpha = MyRippleAlpha } // ... CompositionLocalProvider(LocalRippleTheme provides DisabledRippleThemeColorAndAlpha) { Button { // ... } }
আপনার উপরের স্নিপেটটি এতে সংশোধন করা উচিত:
@OptIn(ExperimentalMaterialApi::class) private val MyRippleConfiguration = RippleConfiguration(color = Color.Red, rippleAlpha = MyRippleAlpha) // ... CompositionLocalProvider(LocalRippleConfiguration provides MyRippleConfiguration) { Button { // ... } }
একটি অ্যাপ্লিকেশনের সমস্ত লহরকে বিশ্বব্যাপী পরিবর্তন করতে RippleTheme ব্যবহার করে
পূর্বে, আপনি থিম-ব্যাপী স্তরে রিপল আচরণ সংজ্ঞায়িত করতে LocalRippleTheme ব্যবহার করতে পারেন। এটি মূলত কাস্টম ডিজাইন সিস্টেম কম্পোজিশন লোকাল এবং রিপলের মধ্যে একটি ইন্টিগ্রেশন পয়েন্ট ছিল। একটি জেনেরিক থিমিং আদিম উন্মুক্ত করার পরিবর্তে, material-ripple এখন একটি createRippleModifierNode() ফাংশন প্রকাশ করে। এই ফাংশনটি ডিজাইন সিস্টেম লাইব্রেরিগুলিকে উচ্চতর অর্ডার wrapper ইমপ্লিমেন্টেশন তৈরি করার অনুমতি দেয়, যা তাদের থিমের মানগুলি জিজ্ঞাসা করে এবং তারপর এই ফাংশন দ্বারা তৈরি নোডে রিপল ইমপ্লিমেন্টেশন অর্পণ করে।
এটি ডিজাইন সিস্টেমগুলিকে তাদের যা প্রয়োজন তা সরাসরি জিজ্ঞাসা করার অনুমতি দেয় এবং material-ripple স্তরে যা সরবরাহ করা হয় তার সাথে সামঞ্জস্য না করে উপরে যেকোন প্রয়োজনীয় ব্যবহারকারী-কনফিগারযোগ্য থিমিং স্তরগুলিকে প্রকাশ করতে দেয়। এই পরিবর্তনটি আরও স্পষ্ট করে যে রিপলটি কোন থিম/স্পেসিফিকেশনের সাথে সঙ্গতিপূর্ণ, কারণ এটি রীপল API নিজেই সেই চুক্তিকে সংজ্ঞায়িত করে, বরং থিম থেকে নিখুঁতভাবে উদ্ভূত হওয়ার পরিবর্তে।
গাইডেন্সের জন্য, মেটেরিয়াল লাইব্রেরিতে রিপল এপিআই ইমপ্লিমেন্টেশন দেখুন এবং আপনার নিজস্ব ডিজাইন সিস্টেমের জন্য প্রয়োজনীয় মেটেরিয়াল কম্পোজিশন লোকালদের কলগুলিকে প্রতিস্থাপন করুন।
Indication থেকে IndicationNodeFactory এ স্থানান্তর করুন
Indication কাছাকাছি পাস
আপনি যদি শুধু একটি Indication তৈরি করেন, যেমন Modifier.clickable বা Modifier.indication এ পাস করার জন্য একটি লহর তৈরি করেন, তাহলে আপনাকে কোনো পরিবর্তন করতে হবে না। IndicationNodeFactory Indication থেকে উত্তরাধিকার সূত্রে প্রাপ্ত, তাই সবকিছু কম্পাইল এবং কাজ চালিয়ে যাবে।
Indication তৈরি করা
আপনি যদি নিজের Indication বাস্তবায়ন তৈরি করেন, তবে বেশিরভাগ ক্ষেত্রে মাইগ্রেশন সহজ হওয়া উচিত। উদাহরণস্বরূপ, একটি Indication বিবেচনা করুন যা প্রেসে একটি স্কেল প্রভাব প্রয়োগ করে:
object ScaleIndication : Indication { @Composable override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance { // key the remember against interactionSource, so if it changes we create a new instance val instance = remember(interactionSource) { ScaleIndicationInstance() } LaunchedEffect(interactionSource) { interactionSource.interactions.collectLatest { interaction -> when (interaction) { is PressInteraction.Press -> instance.animateToPressed(interaction.pressPosition) is PressInteraction.Release -> instance.animateToResting() is PressInteraction.Cancel -> instance.animateToResting() } } } return instance } } private class ScaleIndicationInstance : IndicationInstance { var currentPressPosition: Offset = Offset.Zero val animatedScalePercent = Animatable(1f) suspend fun animateToPressed(pressPosition: Offset) { currentPressPosition = pressPosition animatedScalePercent.animateTo(0.9f, spring()) } suspend fun animateToResting() { animatedScalePercent.animateTo(1f, spring()) } override fun ContentDrawScope.drawIndication() { scale( scale = animatedScalePercent.value, pivot = currentPressPosition ) { this@drawIndication.drawContent() } } }
আপনি এটি দুটি ধাপে স্থানান্তর করতে পারেন:
DrawModifierNodeহতেScaleIndicationInstanceমাইগ্রেট করুন।DrawModifierNodeজন্য API পৃষ্ঠটিIndicationInstanceএর অনুরূপ: এটি একটিContentDrawScope#draw()ফাংশন প্রকাশ করে যা কার্যতIndicationInstance#drawContent()এর সমতুল্য। আপনাকে সেই ফাংশনটি পরিবর্তন করতে হবে, এবং তারপরIndicationপরিবর্তে সরাসরি নোডের ভিতরেcollectLatestযুক্তি প্রয়োগ করতে হবে।উদাহরণস্বরূপ, নিম্নোক্ত স্নিপেট অবনমিত API ব্যবহার করে:
private class ScaleIndicationInstance : IndicationInstance { var currentPressPosition: Offset = Offset.Zero val animatedScalePercent = Animatable(1f) suspend fun animateToPressed(pressPosition: Offset) { currentPressPosition = pressPosition animatedScalePercent.animateTo(0.9f, spring()) } suspend fun animateToResting() { animatedScalePercent.animateTo(1f, spring()) } override fun ContentDrawScope.drawIndication() { scale( scale = animatedScalePercent.value, pivot = currentPressPosition ) { this@drawIndication.drawContent() } } }
আপনার উপরের স্নিপেটটি এতে সংশোধন করা উচিত:
private class ScaleIndicationNode( private val interactionSource: InteractionSource ) : Modifier.Node(), DrawModifierNode { var currentPressPosition: Offset = Offset.Zero val animatedScalePercent = Animatable(1f) private suspend fun animateToPressed(pressPosition: Offset) { currentPressPosition = pressPosition animatedScalePercent.animateTo(0.9f, spring()) } private suspend fun animateToResting() { animatedScalePercent.animateTo(1f, spring()) } override fun onAttach() { coroutineScope.launch { interactionSource.interactions.collectLatest { interaction -> when (interaction) { is PressInteraction.Press -> animateToPressed(interaction.pressPosition) is PressInteraction.Release -> animateToResting() is PressInteraction.Cancel -> animateToResting() } } } } override fun ContentDrawScope.draw() { scale( scale = animatedScalePercent.value, pivot = currentPressPosition ) { this@draw.drawContent() } } }
IndicationNodeFactoryবাস্তবায়ন করতেScaleIndicationমাইগ্রেট করুন। কারণ সংগ্রহের যুক্তি এখন নোডে সরানো হয়েছে, এটি একটি খুব সাধারণ ফ্যাক্টরি অবজেক্ট যার একমাত্র দায়িত্ব একটি নোড উদাহরণ তৈরি করা।উদাহরণস্বরূপ, নিম্নোক্ত স্নিপেট অবনমিত API ব্যবহার করে:
object ScaleIndication : Indication { @Composable override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance { // key the remember against interactionSource, so if it changes we create a new instance val instance = remember(interactionSource) { ScaleIndicationInstance() } LaunchedEffect(interactionSource) { interactionSource.interactions.collectLatest { interaction -> when (interaction) { is PressInteraction.Press -> instance.animateToPressed(interaction.pressPosition) is PressInteraction.Release -> instance.animateToResting() is PressInteraction.Cancel -> instance.animateToResting() } } } return instance } }
আপনার উপরের স্নিপেটটি এতে সংশোধন করা উচিত:
object ScaleIndicationNodeFactory : IndicationNodeFactory { override fun create(interactionSource: InteractionSource): DelegatableNode { return ScaleIndicationNode(interactionSource) } override fun hashCode(): Int = -1 override fun equals(other: Any?) = other === this }
একটি IndicationInstance তৈরি করতে Indication ব্যবহার করে
বেশিরভাগ ক্ষেত্রে, আপনার একটি উপাদানের জন্য Indication প্রদর্শন করতে Modifier.indication ব্যবহার করা উচিত। যাইহোক, বিরল ক্ষেত্রে যে আপনি ম্যানুয়ালি rememberUpdatedInstance ব্যবহার করে একটি IndicationInstance তৈরি করছেন, Indication একটি IndicationNodeFactory কিনা তা পরীক্ষা করার জন্য আপনাকে আপনার বাস্তবায়ন আপডেট করতে হবে যাতে আপনি একটি হালকা বাস্তবায়ন ব্যবহার করতে পারেন। উদাহরণস্বরূপ, Modifier.indication তৈরি করা নোডকে অভ্যন্তরীণভাবে অর্পণ করবে যদি এটি একটি IndicationNodeFactory হয়। যদি তা না হয়, তাহলে এটি rememberUpdatedInstance কল করতে Modifier.composed ব্যবহার করবে।