हमने नए एपीआई लॉन्च किए हैं, ताकि Modifier.clickable
का इस्तेमाल करने वाले इंटरैक्टिव कॉम्पोनेंट की कंपोज़िशन परफ़ॉर्मेंस को बेहतर बनाया जा सके. इन एपीआई की मदद से, ज़्यादा असरदार Indication
लागू किए जा सकते हैं. जैसे, रिपल इफ़ेक्ट.
androidx.compose.foundation:foundation:1.7.0+
और
androidx.compose.material:material-ripple:1.7.0+
में एपीआई से जुड़े ये बदलाव शामिल हैं:
अब सेवा में नहीं है |
डिवाइस बदलना |
---|---|
|
|
|
नई ध्यान दें: इस संदर्भ में, "मटेरियल लाइब्रेरी" का मतलब |
|
इनमें से किसी तरीके को अपनाएं:
|
इस पेज पर, व्यवहार में हुए बदलावों के असर के बारे में बताया गया है. साथ ही, नए एपीआई पर माइग्रेट करने के निर्देश दिए गए हैं.
व्यवहार में बदलाव
लाइब्रेरी के इन वर्शन में, रिपल इफ़ेक्ट के व्यवहार में बदलाव किया गया है:
androidx.compose.material:material:1.7.0+
androidx.compose.material3:material3:1.3.0+
androidx.wear.compose:compose-material:1.4.0+
Material लाइब्रेरी के इन वर्शन में अब rememberRipple()
का इस्तेमाल नहीं किया जाता. इसके बजाय, इनमें नए रिपल एपीआई का इस्तेमाल किया जाता है. इस वजह से, वे LocalRippleTheme
के बारे में क्वेरी नहीं करते.
इसलिए, अगर आपने अपने ऐप्लिकेशन में LocalRippleTheme
सेट किया है, तो मटेरियल कॉम्पोनेंट इन वैल्यू का इस्तेमाल नहीं करेंगे.
यहां दिए गए सेक्शन में, नए एपीआई पर माइग्रेट करने का तरीका बताया गया है.
rememberRipple
से ripple
पर माइग्रेट करना
मटीरियल लाइब्रेरी का इस्तेमाल करना
अगर मटीरियल लाइब्रेरी का इस्तेमाल किया जा रहा है, तो rememberRipple()
को सीधे तौर पर, उससे जुड़ी लाइब्रेरी से ripple()
को कॉल करने वाले फ़ंक्शन से बदलें. यह एपीआई, Material थीम एपीआई से मिली वैल्यू का इस्तेमाल करके रिपल इफ़ेक्ट बनाता है. इसके बाद, वापस मिले ऑब्जेक्ट को Modifier.clickable
और/या अन्य कॉम्पोनेंट को पास करें.
उदाहरण के लिए, इस स्निपेट में ऐसे एपीआई का इस्तेमाल किया गया है जो अब काम नहीं करते:
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()
का इस्तेमाल किया था, तो आपको अपना रिपल एपीआई देना चाहिए. यह रिपल नोड एपीआई को डेलिगेट करता है, जो material-ripple
में दिखता है. इसके बाद, आपके कॉम्पोनेंट अपने रिपल का इस्तेमाल कर सकते हैं. यह रिपल, आपकी थीम की वैल्यू को सीधे तौर पर इस्तेमाल करता है. ज़्यादा जानकारी के लिए, RippleTheme
से माइग्रेट करना लेख पढ़ें.
RippleTheme
से माइग्रेट करना
किसी कॉम्पोनेंट के लिए रिपल इफ़ेक्ट बंद करने के लिए, RippleTheme
का इस्तेमाल करना
material
और material3
लाइब्रेरी, RippleConfiguration
और LocalRippleConfiguration
को दिखाती हैं. इनकी मदद से, किसी सबट्री में रिपल के दिखने के तरीके को कॉन्फ़िगर किया जा सकता है. ध्यान दें कि RippleConfiguration
और LocalRippleConfiguration
एक्सपेरिमेंट के तौर पर उपलब्ध हैं. इनका इस्तेमाल सिर्फ़ हर कॉम्पोनेंट को पसंद के मुताबिक बनाने के लिए किया जाता है. इन एपीआई के साथ, ग्लोबल/थीम के हिसाब से बदलाव करने की सुविधा काम नहीं करती. इस सुविधा के इस्तेमाल के बारे में ज़्यादा जानने के लिए, किसी ऐप्लिकेशन में सभी रिपल को ग्लोबल लेवल पर बदलने के लिए RippleTheme
का इस्तेमाल करना लेख पढ़ें.
उदाहरण के लिए, इस स्निपेट में ऐसे एपीआई का इस्तेमाल किया गया है जो अब काम नहीं करते:
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
एक्सपेरिमेंटल एपीआई हैं. इनका इस्तेमाल सिर्फ़ हर कॉम्पोनेंट को पसंद के मुताबिक बनाने के लिए किया जाता है.
उदाहरण के लिए, इस स्निपेट में ऐसे एपीआई का इस्तेमाल किया गया है जो अब काम नहीं करते:
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
लेयर पर उपलब्ध कॉन्फ़िगरेशन के मुताबिक काम किए बिना, उपयोगकर्ता के हिसाब से कॉन्फ़िगर की जा सकने वाली ज़रूरी थीमिंग लेयर को सबसे ऊपर दिखा सकते हैं. इस बदलाव से यह भी साफ़ तौर पर पता चलता है कि रिपल किस थीम/स्पेसिफ़िकेशन के मुताबिक है. ऐसा इसलिए, क्योंकि रिपल एपीआई ही उस कॉन्ट्रैक्ट को तय करता है. यह थीम से अपने-आप नहीं मिलता.
निर्देशों के लिए, Material लाइब्रेरी में ripple API लागू करने का तरीका देखें. साथ ही, अपने डिज़ाइन सिस्टम के लिए, ज़रूरत के हिसाब से Material कंपोज़िशन लोकल के कॉल बदलें.
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() } } }
इसे दो चरणों में माइग्रेट किया जा सकता है:
ScaleIndicationInstance
सेDrawModifierNode
पर माइग्रेट करें.DrawModifierNode
के लिए एपीआई सर्फ़ेस,IndicationInstance
से काफ़ी मिलता-जुलता है: यहContentDrawScope#draw()
फ़ंक्शन को दिखाता है, जोIndicationInstance#drawContent()
के बराबर है. आपको उस फ़ंक्शन को बदलना होगा. इसके बाद,Indication
के बजाय सीधे नोड मेंcollectLatest
लॉजिक लागू करना होगा.उदाहरण के लिए, इस स्निपेट में ऐसे एपीआई का इस्तेमाल किया गया है जो अब काम नहीं करते:
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
को माइग्रेट करें. कलेक्शन लॉजिक को अब नोड में ले जाया गया है. इसलिए, यह एक बहुत ही सामान्य फ़ैक्ट्री ऑब्जेक्ट है. इसकी ज़िम्मेदारी सिर्फ़ नोड इंस्टेंस बनाना है.उदाहरण के लिए, इस स्निपेट में ऐसे एपीआई का इस्तेमाल किया गया है जो अब काम नहीं करते:
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
है, तो यह बनाए गए नोड को इंटरनल तौर पर असाइन हो जाएगा. अगर ऐसा नहीं है, तो Modifier.composed
, rememberUpdatedInstance
को कॉल करने के लिए इसका इस्तेमाल करेगा.