Indication ve Ripple API'lerine taşıma

Kullanılan etkileşimli bileşenlerin Modifier.clickable, yeni API'leri kullanıma sunduk. Bu API'ler, gibi verimli Indication uygulamaları için de geçerlidir.

androidx.compose.foundation:foundation:1.7.0+ ve androidx.compose.material:material-ripple:1.7.0+ aşağıdaki API'yi içerir değişiklikler:

Kullanımdan kaldırıldı

İkame

Indication#rememberUpdatedInstance

IndicationNodeFactory

rememberRipple()

Bunun yerine Materyal kitaplıklarında yeni ripple() API'leri sağlandı.

Not: Bu bağlamda, "Materyal kitaplıkları" androidx.compose.material:material, androidx.compose.material3:material3, androidx.wear.compose:compose-material ve androidx.wear.compose:compose-material3. anlamına gelir

RippleTheme

Şu iki yöntemden birini kullanın:

  • Materyal Kitaplığı RippleConfiguration API'lerini kullanın veya
  • Kendi tasarım sistemi dalga uygulamanızı oluşturma

Bu sayfada, davranış değişikliğinin etkisi ve kullanıma sunuyoruz.

Davranış değişikliği

Aşağıdaki kitaplık sürümlerinde bir dalga davranışı değişikliği bulunmaktadır:

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

Materyal kitaplıklarının bu sürümlerinde artık rememberRipple() kullanılmıyor; bunun yerine yeni ripple API'lerini kullanıyorlar. Sonuç olarak LocalRippleTheme sorgulanmaz. Dolayısıyla, uygulamanızda LocalRippleTheme özelliğini ayarlarsanız Material bileşenleri bu değerleri kullanmaz.

Aşağıdaki bölümde, geçici olarak eski davranışa nasıl dönüleceği açıklanmaktadır geçiş yapmadan; ancak yeni API'lere geçmenizi öneririz. Örneğin, taşıma talimatları için rememberRipple ürününden ripple ürününe veri taşıma başlıklı makaleyi inceleyin bahsedeceğiz.

Malzeme kitaplığı sürümünü taşımadan yükseltin

Kitaplık sürümlerinin yeni sürüme geçirilmesindeki engellemeyi kaldırmak için geçici Yapılandırılacak LocalUseFallbackRippleImplementation CompositionLocal API Malzeme bileşenleri, eski davranışın yerini alacak:

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

Eski dalgaların görülebilmesi için bunu MaterialTheme dışında sağladığınızdan emin olun LocalIndication aracılığıyla sağlanır.

Aşağıdaki bölümlerde yeni API'lere nasıl geçiş yapılacağı açıklanmaktadır.

rememberRipple - ripple tarihleri arasında taşıyın

Material kitaplığı kullanma

Malzeme kitaplığı kullanıyorsanız rememberRipple() öğesini doğrudan bir çağrıyı ilgili kitaplıktan ripple() adlı kanala taşıyacak. Bu API dalga oluşturuyor kullanarak Materyal Tema API'lerinden türetilen değerleri kullanabilirsiniz. Ardından, döndürülen nesneye Modifier.clickable ve/veya diğer bileşenlere tabidir.

Örneğin, aşağıdaki snippet'te desteği sonlandırılmış API'ler kullanılmaktadır:

Box(
    Modifier.clickable(
        onClick = {},
        interactionSource = remember { MutableInteractionSource() },
        indication = rememberRipple()
    )
) {
    // ...
}

Yukarıdaki snippet'i şu şekilde değiştirmeniz gerekir:

@Composable
private fun RippleExample() {
    Box(
        Modifier.clickable(
            onClick = {},
            interactionSource = remember { MutableInteractionSource() },
            indication = ripple()
        )
    ) {
        // ...
    }
}

ripple() işlevinin artık composable bir işlev olmadığını ve hatırlarsınız. Ayrıca, aşağıdaki gibi birçok bileşende yeniden kullanılabilir: bu nedenle, dalgalanmayı artırmak için dalga oluşturma işlemini üst düzey bir değere kaydetme anlamına gelir.

Özel tasarım sistemini uygulamaya geçirme

Kendi tasarım sisteminizi uyguluyorsanız ve daha önce rememberRipple() ile birlikte özel bir RippleTheme kullanarak dalgayı yapılandırmak için kullanılır. Bunun yerine, ripple düğümüne yetki veren kendi ripple API'nizi sağlamalısınız material-ripple içinde kullanıma sunulan API'ler. Ardından bileşenleriniz kendi Ripple'ınızı kullanabilir gösteren bir grafik oluşturur. Daha fazla bilgi için bkz. Taşıma RippleTheme başlangıç fiyatıyla.

RippleTheme ürününden taşıyın

Davranış değişikliğini geçici olarak devre dışı bırak

Materyal kitaplıklarında geçici bir CompositionLocal bulunur, Tüm ayarları yapılandırmak için kullanabileceğiniz LocalUseFallbackRippleImplementation rememberRipple kullanımına geri dönecek materyal bileşenleri Bu şekilde ekip rememberRipple, LocalRippleTheme sorgusunu sorgulamaya devam ediyor.

Aşağıdaki kod snippet'i, LocalUseFallbackRippleImplementation CompositionLocal API'si:

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

Materyal tabanlı özel bir uygulama teması kullanıyorsanız şunları yapabilirsiniz: Uygulamanızın temasının bir parçası olarak yerel besteyi güvenli bir şekilde sağlayın:

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun MyAppTheme(content: @Composable () -> Unit) {
    CompositionLocalProvider(LocalUseFallbackRippleImplementation provides true) {
        MaterialTheme(content = content)
    }
}

Daha fazla bilgi için taşıma bölümünü inceleyebilirsiniz.

Belirli bir bileşende dalgayı devre dışı bırakmak için RippleTheme kullanma

material ve material3 kitaplıkları, RippleConfiguration ve LocalRippleConfiguration gibi, reklam öğelerinin görünümünü yapılandırmanız için dalgalar oluşturuyor. RippleConfiguration ve LocalRippleConfiguration deneyseldir ve yalnızca bileşen başına tasarlanmıştır. birçok seçenek var. Genel/tema genelinde özelleştirme, aşağıdakilerle desteklenmez API'ler Bir tablodaki tüm dalgaları küresel olarak değiştirmek için RippleTheme bakın.

Örneğin, aşağıdaki snippet'te desteği sonlandırılmış API'ler kullanılmaktadır:

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 {
            // ...
        }
    }

Yukarıdaki snippet'i şu şekilde değiştirmeniz gerekir:

CompositionLocalProvider(LocalRippleConfiguration provides null) {
    Button {
        // ...
    }
}

Belirli bir bileşende bir dalganın rengini/alfasını değiştirmek için RippleTheme kullanma

Önceki bölümde açıklandığı gibi, RippleConfiguration ve LocalRippleConfiguration, deneysel API'lerdir ve yalnızca şunun için tasarlanmıştır: her bileşende özelleştirilebilir.

Örneğin, aşağıdaki snippet'te desteği sonlandırılmış API'ler kullanılmaktadır:

private object DisabledRippleThemeColorAndAlpha : RippleTheme {

    @Composable
    override fun defaultColor(): Color = Color.Red

    @Composable
    override fun rippleAlpha(): RippleAlpha = MyRippleAlpha
}

// ...
    CompositionLocalProvider(LocalRippleTheme provides DisabledRippleThemeColorAndAlpha) {
        Button {
            // ...
        }
    }

Yukarıdaki snippet'i şu şekilde değiştirmeniz gerekir:

@OptIn(ExperimentalMaterialApi::class)
private val MyRippleConfiguration =
    RippleConfiguration(color = Color.Red, rippleAlpha = MyRippleAlpha)

// ...
    CompositionLocalProvider(LocalRippleConfiguration provides MyRippleConfiguration) {
        Button {
            // ...
        }
    }

Bir uygulamadaki tüm dalgaları genel olarak değiştirmek için RippleTheme kullanma

Önceden, belirli bir düzeyde dalga davranışını tanımlamak için LocalRippleTheme kullanılabilmekteydi seviyesidir. Bu temelde özel kanallar arasındaki dalgalar ve tasarımlar hakkında daha fazla bilgi edindiniz. Genel bir kitle iletişimini tema temel öğesi, material-ripple artık bir createRippleModifierNode() gösteriyor işlevini kullanın. Bu işlev, tasarım sistem kitaplıklarının daha yüksek wrapper uygulaması için sipariş verip tema değerlerini sorgulayan dalga uygulamasını bu işlev tarafından oluşturulan düğüme uygular.

Bu, tasarım sistemlerinin ihtiyaç duyduklarını doğrudan sorgulamasına ve kullanıcının teklif beklentilerini üst tarafta, kullanıcı tarafından yapılandırılabilen tema katmanları material-ripple katmanında sağlanan verilerdir. Bu değişiklik sayesinde dalganın hangi temaya/spesifikasyona uyduğunu açıkça belirtmelisiniz. Dolaylı değil, bu sözleşmeyi tanımlayan ripple API'nin kendisi edinilmesini de sağlar.

Yardım için Material'daki ripple API uygulaması bölümüne bakın. gereken şekilde Malzeme bileşimi yerellerine yapılan çağrıların yerine geliştirebilirsiniz.

Indication - IndicationNodeFactory tarihleri arasında taşıyın

Indication civarında

Yalnızca aktarmak amacıyla bir Indication oluşturuyorsanız, örneğin bir Modifier.clickable veya Modifier.indication için dalga geçişi, siz geçmez veya değişiklik yapmanız gerekmiyor. IndicationNodeFactory, şuradan devralır: Indication, Böylece her şey derlenmeye ve çalışmaya devam eder.

Indication oluşturuluyor

Kendi Indication uygulamanızı oluşturuyorsanız taşıma işlemi çoğu durumda basit olabilir. Örneğin, aynı durumdaki bir Indication basıldığında ölçek efekti:

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

Bunu iki adımda taşıyabilirsiniz:

  1. ScaleIndicationInstance e-posta adresini DrawModifierNode olacak şekilde taşıyın. API yüzeyi DrawModifierNode için IndicationInstance ile çok benzerdir: Bir işlevsel olarak eşdeğer olan ContentDrawScope#draw() işlevi IndicationInstance#drawContent(). Bu işlevi değiştirmeniz ve ardından yerine doğrudan düğümün içinde collectLatest mantığını uygulayın. Indication.

    Örneğin, aşağıdaki snippet'te desteği sonlandırılmış API'ler kullanılmaktadır:

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

    Yukarıdaki snippet'i şu şekilde değiştirmeniz gerekir:

    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 uygulamasını uygulamak için ScaleIndication verilerini taşıyın. Çünkü toplama mantığı artık düğüme taşınıyor. Bu, çok basit bir fabrika tek sorumluluğu düğüm örneği oluşturmak olan bir nesnedir.

    Örneğin, aşağıdaki snippet'te desteği sonlandırılmış API'ler kullanılmaktadır:

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

    Yukarıdaki snippet'i şu şekilde değiştirmeniz gerekir:

    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 oluşturmak için Indication kullanılıyor

Çoğu durumda, Modifier.indication parametresini kullanarak birIndication bir bileşenidir. Ancak, manuel olarak bir IndicationInstance, rememberUpdatedInstance kullanıyor, Indication öğesinin bir IndicationNodeFactory olup olmadığını kontrol etmek için daha hafif bir uygulama kullanabilirsiniz. Örneğin, Modifier.indication IndicationNodeFactory ise oluşturulan düğüme dahili olarak yetki verir. Eğer değil, rememberUpdatedInstance çağrısı için Modifier.composed kullanılır.