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ı" ifadesi |
|
Ş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ışıyla ilgili bir 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
Material kitaplığı kullanıyorsanız rememberRipple() öğesini doğrudan ilgili kitaplıktan 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ılmaktadır:
Box( Modifier.clickable( onClick = {}, interactionSource = remember { MutableInteractionSource() }, indication = rememberRipple() ) ) { // ... }
Yukarıdaki snippet'i aşağıdaki gibi 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, tahsisleri kaydetmek için dalgalanma oluşturma işlemini üst düzey bir değere çıkarmanız önerilir.
Özel tasarım sistemini 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 içinde 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 öğelerinin yalnızca bileşen başına özelleştirme için kullanıldığı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ı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 aşağıdaki gibi 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 yalnızca bileşen başına özelleştirme için tasarlanmıştır.
Ö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 aşağıdaki gibi 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ı. material-ripple, genel bir tema oluşturma öğesi sunmak yerine artık bir createRippleModifierNode() işlevi sunuyor. Bu işlev, tasarım sistemi kitaplıklarının daha yüksek düzeyde wrapper uygulama oluşturmasına olanak tanır. Bu uygulamalar, 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/şartnameye uygun olduğunu daha açık hale getirir. Çünkü bu sözleşmeyi tema değil, dalgalanma API'si tanımlar.
Yol gösterici bilgiler için Material kitaplıklarındaki ripple API uygulamasını inceleyin ve Material composition yerellerine yapılan çağrıları kendi tasarım sisteminize göre gerektiği şekilde değiştirin.
Indication alanından IndicationNodeFactory alanına taşıma
Indication civarında geçiş
Yalnızca Indication oluşturup paylaşmak istiyorsanız (ör. Modifier.clickable veya Modifier.indication'a göndermek için 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 kolay 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() } } }
Bunu iki adımda taşıyabilirsiniz:
ScaleIndicationInstance,DrawModifierNodeolarak taşınır.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ı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 aşağıdaki gibi 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, tek sorumluluğu bir düğüm örneği oluşturmak olan çok basit bir fabrika nesnesidir.Ö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 aşağıdaki gibi 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şen için Indication öğesini görüntülemek üzere 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 devreder. Aksi takdirde, rememberUpdatedInstance'ı aramak için Modifier.composed kullanılır.