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-এ স্থানান্তরিত করার পরামর্শ দিই। মাইগ্রেশন নির্দেশাবলীর জন্য, rememberRipple
থেকে ripple
এবং পরবর্তী বিভাগগুলিতে মাইগ্রেট দেখুন।
স্থানান্তর ছাড়াই উপাদান লাইব্রেরি সংস্করণ আপগ্রেড করুন
আপগ্রেড লাইব্রেরি সংস্করণ আনব্লক করতে, আপনি পুরানো আচরণে ফিরে আসার জন্য উপাদান উপাদানগুলি কনফিগার করতে অস্থায়ী LocalUseFallbackRippleImplementation CompositionLocal
API ব্যবহার করতে পারেন:
CompositionLocalProvider(LocalUseFallbackRippleImplementation provides true) { MaterialTheme { App() } }
MaterialTheme
বাইরে এটি প্রদান করা নিশ্চিত করুন যাতে LocalIndication
এর মাধ্যমে পুরানো রিপলস প্রদান করা যায়।
নিম্নলিখিত বিভাগগুলি বর্ণনা করে যে কীভাবে নতুন API-এ স্থানান্তর করা যায়।
rememberRipple
থেকে ripple
মাইগ্রেট করুন
একটি উপাদান লাইব্রেরি ব্যবহার করে
আপনি যদি একটি ম্যাটেরিয়াল লাইব্রেরি ব্যবহার করেন, তাহলে সংশ্লিষ্ট লাইব্রেরি থেকে 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
থেকে মাইগ্রেট করুন
সাময়িকভাবে আচরণ পরিবর্তন অপ্ট আউট
ম্যাটেরিয়াল লাইব্রেরিগুলির একটি অস্থায়ী CompositionLocal
, LocalUseFallbackRippleImplementation
আছে, যা আপনি rememberRipple
ব্যবহার করে ফিরে আসার জন্য সমস্ত উপাদান উপাদান কনফিগার করতে ব্যবহার করতে পারেন। এইভাবে, rememberRipple
LocalRippleTheme
জিজ্ঞাসা করতে থাকে।
নিম্নলিখিত কোড স্নিপেট প্রদর্শন করে কিভাবে LocalUseFallbackRippleImplementation CompositionLocal
API ব্যবহার করতে হয়:
CompositionLocalProvider(LocalUseFallbackRippleImplementation provides true) { MaterialTheme { App() } }
আপনি যদি একটি কাস্টম অ্যাপ থিম ব্যবহার করেন যা উপাদানের উপরে তৈরি করা হয়, তাহলে আপনি আপনার অ্যাপের থিমের অংশ হিসেবে সুরক্ষিতভাবে কম্পোজিশন স্থানীয় প্রদান করতে পারেন:
@OptIn(ExperimentalMaterialApi::class) @Composable fun MyAppTheme(content: @Composable () -> Unit) { CompositionLocalProvider(LocalUseFallbackRippleImplementation provides true) { MaterialTheme(content = content) } }
আরও তথ্যের জন্য, স্থানান্তরিত না করে আপগ্রেড মেটেরিয়াল লাইব্রেরি সংস্করণ দেখুন।
একটি প্রদত্ত উপাদানের জন্য একটি লহর নিষ্ক্রিয় করতে 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
ব্যবহার করবে।