Modifier.clickable kullanan etkileşimli bileşenlerin oluşturma performansını artırmak için yeni API'ler kullanıma sunduk. Bu API'ler, dalgalanma gibi daha verimli Indication uygulamalara olanak tanır.
androidx.compose.foundation:foundation:1.7.0+ ve androidx.compose.material:material-ripple:1.7.0+ aşağıdaki API değişikliklerini içerir:
Kullanımdan kaldırıldı |
Değiştirme |
|---|---|
|
|
|
Yeni Not: Bu bağlamda "Materyal kitaplıkları" |
|
Şu iki yöntemden birini kullanın:
|
Bu sayfada, davranış değişikliğinin etkisi ve yeni API'lere geçişle ilgili talimatlar açıklanmaktadır.
Davranış değişikliği
Aşağıdaki kitaplık sürümlerinde dalgalanma davranışında değişiklik yapıldı:
androidx.compose.material:material:1.7.0+androidx.compose.material3:material3:1.3.0+androidx.wear.compose:compose-material:1.4.0+
Material kitaplıklarının bu sürümleri artık rememberRipple() kullanmıyor. Bunun yerine yeni dalgalanma API'lerini kullanıyor. Bu nedenle LocalRippleTheme sorgusu yapmazlar.
Bu nedenle, uygulamanızda LocalRippleTheme değerini ayarlarsanız Material bileşenleri bu değerleri kullanmaz.
Aşağıdaki bölümlerde yeni API'lere nasıl geçiş yapılacağı açıklanmaktadır.
rememberRipple alanından ripple alanına taşıma
Malzeme kitaplığı kullanma
Bir Material kitaplığı kullanıyorsanız rememberRipple() öğesini doğrudan ilgili kitaplıktaki ripple() çağrısıyla değiştirin. Bu API, Material teması API'lerinden türetilen değerleri kullanarak bir dalgalanma oluşturur. Ardından, döndürülen nesneyi Modifier.clickable ve/veya diğer bileşenlere iletin.
Örneğin, aşağıdaki snippet'te desteği sonlandırılmış API'ler kullanılıyor:
Box( Modifier.clickable( onClick = {}, interactionSource = remember { MutableInteractionSource() }, indication = rememberRipple() ) ) { // ... }
Yukarıdaki snippet'i şu şekilde değiştirmelisiniz:
@Composable private fun RippleExample() { Box( Modifier.clickable( onClick = {}, interactionSource = remember { MutableInteractionSource() }, indication = ripple() ) ) { // ... } }
ripple() artık birleştirilebilir bir işlev değildir ve hatırlanması gerekmez. Ayrıca, değiştiricilere benzer şekilde birden fazla bileşende yeniden kullanılabilir. Bu nedenle, ayırmaları kaydetmek için dalgalanma oluşturma işlemini üst düzey bir değere çıkarmanız önerilir.
Özel tasarım sistemi uygulama
Kendi tasarım sisteminizi uyguluyorsanız ve daha önce dalgalanmayı yapılandırmak için özel bir RippleTheme ile birlikte rememberRipple() kullanıyorsanız bunun yerine material-ripple'de kullanıma sunulan dalgalanma düğümü API'lerine temsilci atayan kendi dalgalanma API'nizi sağlamanız gerekir. Ardından, bileşenleriniz tema değerlerinizi doğrudan kullanan kendi dalgalanma efektinizi kullanabilir. Daha fazla bilgi için RippleTheme başlıklı makaleyi inceleyin.
Taşıma kaynağı: RippleTheme
Belirli bir bileşenin dalgalanmasını devre dışı bırakmak için RippleTheme kullanma
material ve material3 kitaplıkları, bir alt ağaçtaki dalgalanmaların görünümünü yapılandırmanıza olanak tanıyan RippleConfiguration ve LocalRippleConfiguration öğelerini kullanıma sunar. RippleConfiguration ve LocalRippleConfiguration özelliklerinin deneysel olduğunu ve yalnızca bileşen bazında özelleştirme için tasarlandığını unutmayın. Bu API'lerde genel/tema genelinde özelleştirme desteklenmez. Bu kullanım alanı hakkında daha fazla bilgi için Bir uygulamadaki tüm dalgalanmaları genel olarak değiştirmek için RippleTheme kullanma başlıklı makaleyi inceleyin.
Örneğin, aşağıdaki snippet'te desteği sonlandırılmış API'ler kullanılıyor:
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ştirmelisiniz:
CompositionLocalProvider(LocalRippleConfiguration provides null) { Button { // ... } }
Belirli bir bileşenin dalgalanma 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 bileşen bazında özelleştirme için tasarlanmıştır.
Örneğin, aşağıdaki snippet'te desteği sonlandırılmış API'ler kullanılıyor:
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ştirmelisiniz:
@OptIn(ExperimentalMaterialApi::class) private val MyRippleConfiguration = RippleConfiguration(color = Color.Red, rippleAlpha = MyRippleAlpha) // ... CompositionLocalProvider(LocalRippleConfiguration provides MyRippleConfiguration) { Button { // ... } }
Bir uygulamadaki tüm dalgalanmaları genel olarak değiştirmek için RippleTheme kullanma
Daha önce, tema genelinde dalgalanma davranışını tanımlamak için LocalRippleTheme kullanılabiliyordu. Bu, temelde özel tasarım sistemi kompozisyon yerelleri ile ripple arasındaki bir entegrasyon noktasıydı. Genel bir tema oluşturma öğesi kullanmak yerine, material-ripple artık createRippleModifierNode() işlevini kullanıyor. Bu işlev, tasarım sistemi kitaplıklarının daha yüksek düzeyde wrapper uygulama oluşturmasına olanak tanır. Bu uygulama, tema değerlerini sorgular ve ardından dalgalanma uygulamasını bu işlev tarafından oluşturulan düğüme devreder.
Bu sayede tasarım sistemleri, ihtiyaç duyduklarını doğrudan sorgulayabilir ve material-ripple katmanında sağlananlara uymak zorunda kalmadan, gerekli kullanıcı tarafından yapılandırılabilen temalandırma katmanlarını üstte gösterebilir. Bu değişiklik, dalgalanmanın hangi temaya/özelliğe uygun olduğunu daha açık hale getirir. Çünkü bu sözleşmeyi tema değil, dalgalanma API'si tanımlar.
Yardım için Material kitaplıklarındaki ripple API uygulamasını inceleyin ve kendi tasarım sisteminiz için Material composable'larına yapılan çağrıları gerektiği gibi değiştirin.
Indication alanından IndicationNodeFactory alanına taşıma
Indication civarında geçiş
Yalnızca paylaşmak için bir Indication oluşturuyorsanız (ör. Modifier.clickable veya Modifier.indication'ye göndermek için bir dalga oluşturma) herhangi bir değişiklik yapmanız gerekmez. IndicationNodeFactory, Indication öğesinden devralındığı için her şey derlenmeye ve çalışmaya devam eder.
Indication oluşturuluyor
Kendi Indication uygulamanızı oluşturuyorsanız çoğu durumda taşıma işlemi basit olacaktır. Örneğin, basıldığında ölçek efekti uygulayan bir Indication düşünün:
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() } } }
Bu işlemi iki adımda gerçekleştirebilirsiniz:
ScaleIndicationInstanceöğesiniDrawModifierNodeolarak taşıyın.DrawModifierNodeiçin API yüzeyi,IndicationInstanceile çok benzerdir:IndicationInstance#drawContent()ile işlevsel olarak eşdeğer olan birContentDrawScope#draw()işlevini kullanıma sunar. Bu işlevi değiştirmeniz ve ardındancollectLatestmantığınıIndicationyerine doğrudan düğümün içinde uygulamanız gerekir.Örneğin, aşağıdaki snippet'te desteği sonlandırılmış API'ler kullanılıyor:
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ştirmelisiniz:
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'ı uygulamak içinScaleIndication'ı taşıyın. Toplama mantığı artık düğüme taşındığından bu, yalnızca bir düğüm örneği oluşturmaktan sorumlu olan çok basit bir fabrika nesnesidir.Örneğin, aşağıdaki snippet'te desteği sonlandırılmış API'ler kullanılıyor:
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ştirmelisiniz:
object ScaleIndicationNodeFactory : IndicationNodeFactory { override fun create(interactionSource: InteractionSource): DelegatableNode { return ScaleIndicationNode(interactionSource) } override fun hashCode(): Int = -1 override fun equals(other: Any?) = other === this }
Indication kullanarak IndicationInstance oluşturma
Çoğu durumda, bir bileşenin Indication özelliğini görüntülemek için Modifier.indication kullanmalısınız. Ancak nadir durumlarda IndicationInstance öğesini rememberUpdatedInstance kullanarak manuel olarak oluşturuyorsanız daha hafif bir uygulama kullanabilmek için uygulamanızı Indication öğesinin IndicationNodeFactory olup olmadığını kontrol edecek şekilde güncellemeniz gerekir. Örneğin, Modifier.indication, IndicationNodeFactory ise dahili olarak oluşturulan düğüme temsilci olarak atanır. Aksi takdirde, rememberUpdatedInstance'ı aramak için Modifier.composed kullanılır.