Dokunma etkinlikleri ve animasyonlarla çalışırken, yalnızca animasyonlarla çalışırken dikkate almamız gereken birkaç nokta vardır. Öncelikle, kullanıcı etkileşimi en yüksek önceliğe sahip olması gerektiğinden, dokunma etkinlikleri başladığında devam eden bir animasyonu kesmemiz gerekebilir.
Aşağıdaki örnekte, daire bileşeninin ofset konumunu temsil etmek için bir Animatable
kullanılmıştır. Dokunma etkinlikleri
pointerInput
değiştirici ile işlenir. Yeni bir dokunma etkinliği algıladığımızda, ofset değerini dokunma konumuna hareket ettirmek için animateTo
yöntemini çağırırız. Dokunma etkinliği animasyon sırasında da gerçekleşebilir. Bu durumda, animateTo
devam eden animasyonu keser ve kesilen animasyonun hızını korurken animasyonu yeni hedef konuma başlatır.
@Composable fun Gesture() { val offset = remember { Animatable(Offset(0f, 0f), Offset.VectorConverter) } Box( modifier = Modifier .fillMaxSize() .pointerInput(Unit) { coroutineScope { while (true) { // Detect a tap event and obtain its position. awaitPointerEventScope { val position = awaitFirstDown().position launch { // Animate to the tap position. offset.animateTo(position) } } } } } ) { Circle(modifier = Modifier.offset { offset.value.toIntOffset() }) } } private fun Offset.toIntOffset() = IntOffset(x.roundToInt(), y.roundToInt())
Sık karşılaşılan bir diğer kalıp da, animasyon değerlerini sürükleme gibi dokunma etkinliklerinden
gelen değerlerle senkronize etmemizin gerekmesidir. Aşağıdaki örnekte, "SwipeToDismiss
composable'ı kullanmak yerine) "kapatmak için kaydırma" işleminin Modifier
olarak uygulandığını görüyoruz. Öğenin yatay ofseti, Animatable
olarak gösterilir. Bu API'nin, hareket animasyonunda faydalı bir özelliği var. Değeri, animasyonun yanı sıra dokunma etkinlikleri tarafından da değiştirilebilir. Bir dokunma etkinliği aldığımızda, devam eden animasyonlara müdahale edilmesi için Animatable
işlemini stop
yöntemiyle durdururuz.
Bir sürükleme etkinliği sırasında Animatable
değerini, dokunma etkinliklerinden hesaplanan değerle güncellemek için snapTo
kullanırız. Compose, hızlıca kaydırma için sürükleme etkinliklerini kaydetmek ve hızı hesaplamak için VelocityTracker
sağlar. Hız, uçma animasyonu için doğrudan animateDecay
öğesine beslenebilir. Ofset değerini tekrar orijinal konumuna kaydırmak istediğimizde animateTo
yöntemiyle 0f
hedef ofset değerini belirtiriz.
fun Modifier.swipeToDismiss( onDismissed: () -> Unit ): Modifier = composed { val offsetX = remember { Animatable(0f) } pointerInput(Unit) { // Used to calculate fling decay. val decay = splineBasedDecay<Float>(this) // Use suspend functions for touch events and the Animatable. coroutineScope { while (true) { val velocityTracker = VelocityTracker() // Stop any ongoing animation. offsetX.stop() awaitPointerEventScope { // Detect a touch down event. val pointerId = awaitFirstDown().id horizontalDrag(pointerId) { change -> // Update the animation value with touch events. launch { offsetX.snapTo( offsetX.value + change.positionChange().x ) } velocityTracker.addPosition( change.uptimeMillis, change.position ) } } // No longer receiving touch events. Prepare the animation. val velocity = velocityTracker.calculateVelocity().x val targetOffsetX = decay.calculateTargetValue( offsetX.value, velocity ) // The animation stops when it reaches the bounds. offsetX.updateBounds( lowerBound = -size.width.toFloat(), upperBound = size.width.toFloat() ) launch { if (targetOffsetX.absoluteValue <= size.width) { // Not enough velocity; Slide back. offsetX.animateTo( targetValue = 0f, initialVelocity = velocity ) } else { // The element was swiped away. offsetX.animateDecay(velocity, decay) onDismissed() } } } } } .offset { IntOffset(offsetX.value.roundToInt(), 0) } }
Sizin için önerilenler
- Not: Bağlantı metni JavaScript kapalıyken görüntülenir
- Değere dayalı animasyonlar
- Sürükleme, kaydırma ve hızla kaydırma
- Hareketleri anlama