เราต้องคำนึงถึงหลายๆ อย่างเมื่อทำงาน ด้วยเหตุการณ์การแตะและภาพเคลื่อนไหว เมื่อเทียบกับตอนที่เราทำงานกับ ภาพเคลื่อนไหวอย่างเดียว อย่างแรกเลย เราอาจต้องขัดจังหวะภาพเคลื่อนไหวที่ดำเนินอยู่ก่อน เมื่อกิจกรรมการแตะเริ่มขึ้น เนื่องจากการโต้ตอบของผู้ใช้ควรมีลำดับความสำคัญสูงสุด
ในตัวอย่างด้านล่าง เราใช้ Animatable
เพื่อแสดงตำแหน่งออฟเซ็ตของ
คอมโพเนนต์วงกลม กิจกรรมการสัมผัสจะได้รับการประมวลผลด้วย
pointerInput
แป้นกดร่วม เมื่อตรวจพบเหตุการณ์การแตะใหม่ เราจะเรียกใช้ animateTo
เพื่อทำให้
ให้เป็นตำแหน่งการแตะ เหตุการณ์การแตะอาจเกิดขึ้นระหว่างภาพเคลื่อนไหว
และในกรณีดังกล่าว animateTo
จะขัดจังหวะภาพเคลื่อนไหวที่กำลังแสดงและเริ่มเล่น
ภาพเคลื่อนไหวไปยังตำแหน่งเป้าหมายใหม่ขณะที่รักษาความเร็วของ
ภาพเคลื่อนไหวที่ถูกขัดจังหวะ
@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())
อีกรูปแบบหนึ่งที่มักพบบ่อยคือเราต้องซิงค์ค่าของภาพเคลื่อนไหวกับค่าต่างๆ
ที่มาจากกิจกรรมการสัมผัส เช่น การลาก ในตัวอย่างด้านล่าง เราเห็น "ปัดไปที่
ปิด" มีการใช้งานเป็น Modifier
(แทนที่จะใช้
SwipeToDismiss
Composable) ออฟเซ็ตแนวนอนขององค์ประกอบจะแสดงเป็น
Animatable
API นี้มีลักษณะที่เป็นประโยชน์ในภาพเคลื่อนไหวของท่าทางสัมผัส คือ
สามารถเปลี่ยนค่าได้โดยเหตุการณ์การแตะและภาพเคลื่อนไหว เมื่อเราได้รับ
เหตุการณ์แตะลง เราจะหยุด Animatable
ตามเมธอด stop
เพื่อให้
ภาพเคลื่อนไหวต่อเนื่องจะถูกดักจับ
ระหว่างเหตุการณ์การลาก เราจะใช้ snapTo
เพื่ออัปเดตค่า Animatable
ด้วยฟังก์ชัน
ที่คำนวณจากกิจกรรมการสัมผัส Compose จะมีฟีเจอร์สำหรับการสะบัด
VelocityTracker
เพื่อบันทึกเหตุการณ์การลากและคำนวณอัตราความเร็ว ความเร็วอาจ
จะถูกป้อนไปยัง animateDecay
โดยตรงสำหรับภาพเคลื่อนไหวแบบสะบัด เมื่อเราต้องการเลื่อน
ค่าออฟเซ็ตกลับไปยังตำแหน่งเดิม เราจะระบุออฟเซ็ตเป้าหมาย
ของ 0f
โดยใช้เมธอด animateTo
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) } }
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ภาพเคลื่อนไหวตามมูลค่า
- ลาก ปัด และปัดนิ้ว
- ทำความเข้าใจท่าทางสัมผัส