इंडीकेशन और रिपल एपीआई पर माइग्रेट करें

इंटरैक्टिव कॉम्पोनेंट की कंपोज़िशन परफ़ॉर्मेंस को बेहतर बनाने के लिए, Modifier.clickable, हमने नए एपीआई जोड़े हैं. इन एपीआई की मदद से, Indication को लागू करने की बेहतर सुविधा, जैसे कि रिपल.

androidx.compose.foundation:foundation:1.7.0+ और androidx.compose.material:material-ripple:1.7.0+ में यह एपीआई शामिल है बदलाव:

अब काम नहीं करता

डिवाइस बदलना

Indication#rememberUpdatedInstance

IndicationNodeFactory

rememberRipple()

इसके बजाय, मटीरियल लाइब्रेरी में नए ripple() एपीआई उपलब्ध कराए गए हैं.

ध्यान दें: इस संदर्भ में, "मटीरियल लाइब्रेरी" androidx.compose.material:material, androidx.compose.material3:material3, androidx.wear.compose:compose-material, और androidx.wear.compose:compose-material3. का रेफ़रंस देता है

RippleTheme

इनमें से किसी तरीके को अपनाएं:

  • Material लाइब्रेरी के RippleConfiguration एपीआई इस्तेमाल करें या
  • अपना खुद का डिज़ाइन सिस्टम रिपल लागू करें

इस पेज पर, डेटा माइग्रेट करने के तरीके में हुए बदलाव के असर और इस पर माइग्रेट करने से जुड़े निर्देशों की जानकारी दी गई है का उपयोग कर सकते हैं.

व्यवहार में बदलाव

नीचे दिए गए लाइब्रेरी वर्शन में रिपल व्यवहार बदलाव शामिल है:

  • androidx.compose.material:material:1.7.0+
  • androidx.compose.material3:material3:1.3.0+
  • androidx.wear.compose:compose-material:1.4.0+

Material लाइब्रेरी के ये वर्शन अब rememberRipple() का इस्तेमाल नहीं करते; इसके बजाय, वे नए Riple API का इस्तेमाल करते हैं. इस वजह से, वे LocalRippleTheme के लिए क्वेरी नहीं करते हैं. इसलिए, अगर आप अपने ऐप्लिकेशन में LocalRippleTheme को सेट करते हैं, तो मटीरियल कॉम्पोनेंट, इन वैल्यू का इस्तेमाल नहीं करेंगे.

इस सेक्शन में बताया गया है कि कुछ समय के लिए, पुराने तरीके से कैसे वापस आया जा सकता है डेटा माइग्रेट किए बिना; हमारा सुझाव है कि नए एपीआई पर माइग्रेट करें. इसके लिए माइग्रेशन के निर्देश, rememberRipple से ripple पर माइग्रेट करें देखें और बाद के सेक्शन में.

माइग्रेट किए बिना Material लाइब्रेरी के वर्शन को अपग्रेड करें

लाइब्रेरी के वर्शन को अपग्रेड करने से रोकने के लिए, आप कुछ समय के लिए कॉन्फ़िगर करने के लिए LocalUseFallbackRippleImplementation CompositionLocal एपीआई पुराने व्यवहार में वापस आने वाले मटीरियल कॉम्पोनेंट:

CompositionLocalProvider(LocalUseFallbackRippleImplementation provides true) {
    MaterialTheme {
        App()
    }
}

इसे MaterialTheme के बाहर ज़रूर दें, ताकि पुराने रिपल्स ये काम कर सकें LocalIndication के ज़रिए उपलब्ध कराया जाएगा.

नीचे दिए सेक्शन में, नए एपीआई पर माइग्रेट करने का तरीका बताया गया है.

rememberRipple से ripple पर माइग्रेट करें

Material लाइब्रेरी का इस्तेमाल करना

अगर आप मटीरियल लाइब्रेरी का इस्तेमाल कर रहे हैं, तो rememberRipple() को सीधे इस संबंधित लाइब्रेरी से ripple() को किया गया कॉल. यह एपीआई एक रिपल बनाता है मटीरियल थीम एपीआई से मिली वैल्यू का इस्तेमाल करता है. इसके बाद, ऑब्जेक्ट को 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 से माइग्रेट करें

व्यवहार में बदलाव से अस्थायी रूप से ऑप्ट आउट करें

मटीरियल लाइब्रेरी में अस्थायी CompositionLocal, LocalUseFallbackRippleImplementation, जिसका इस्तेमाल करके सभी को कॉन्फ़िगर किया जा सकता है rememberRipple का इस्तेमाल करने के लिए बनाए गए मटीरियल कॉम्पोनेंट. इस तरह, rememberRipple, LocalRippleTheme के बारे में क्वेरी करना जारी रखता है.

नीचे दिया गया कोड स्निपेट LocalUseFallbackRippleImplementation CompositionLocal एपीआई:

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, एक्सपेरिमेंट के तौर पर उपलब्ध हैं और इन्हें सिर्फ़ हर कॉम्पोनेंट के लिए इस्तेमाल किया जा सकता है पसंद के मुताबिक बनाने की सुविधा मिलती है. इनका ग्लोबल/थीम-वाइड कस्टमाइज़ेशन काम नहीं करता एपीआई; देखें कि किसी खास फ़ंक्शन में सभी रिपल को दुनिया भर में बदलने के लिए 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 लेयर में दी जाती है. इस बदलाव से ज़्यादा कमाई भी होगी साफ़ तौर पर बताएं कि रिपल किस थीम/विनिर्देश के मुताबिक है, क्योंकि यह वह भी Repple API के साथ जो उस अनुबंध को परिभाषित करता है, न कि अस्पष्ट रूप से जिसे थीम से लिया गया हो.

दिशा-निर्देशों के लिए, मटीरियल में Reple 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()
        }
    }
}

इसे दो चरणों में माइग्रेट किया जा सकता है:

  1. DrawModifierNode के तौर पर ScaleIndicationInstance को माइग्रेट करें. एपीआई प्लैटफ़ॉर्म DrawModifierNode, IndicationInstance से बहुत मिलता-जुलता है: यह ContentDrawScope#draw() फ़ंक्शन जो फ़ंक्शनल रूप से इसके बराबर है IndicationInstance#drawContent(). आपको वह फ़ंक्शन बदलना होगा और फिर इसके बजाय, सीधे नोड में collectLatest लॉजिक को लागू करें Indication.

    उदाहरण के लिए, नीचे दिए गए स्निपेट में ऐसे एपीआई का इस्तेमाल किया गया है जो अब काम नहीं करते:

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

  2. 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 का इस्तेमाल किया जा रहा है

ज़्यादातर मामलों में, आपको Modifier.indication का इस्तेमाल करके,Indication कॉम्पोनेंट. हालांकि, बहुत कम मामलों में जब आप मैन्युअल रूप से rememberUpdatedInstance का इस्तेमाल करके IndicationInstance, आपको अपना लागू करके जांचे कि Indication एक IndicationNodeFactory है या नहीं, ताकि आप आसान तरीके से लागू किया जा सकता है. उदाहरण के लिए, Modifier.indication अगर यह IndicationNodeFactory है, तो बनाए गए नोड को आंतरिक तौर पर डेलिगेट करते हैं. अगर आपने नहीं, तो इससे rememberUpdatedInstance को कॉल करने के लिए Modifier.composed का इस्तेमाल होगा.