هنگام کار با رویدادها و انیمیشن های لمسی، در مقایسه با زمانی که به تنهایی با انیمیشن کار می کنیم، باید چندین چیز را در نظر بگیریم. اول از همه، ممکن است نیاز داشته باشیم که وقتی رویدادهای لمسی شروع میشوند، یک انیمیشن در حال انجام را قطع کنیم زیرا تعامل کاربر باید بالاترین اولویت را داشته باشد.
در مثال زیر، ما از 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())
الگوی رایج دیگر این است که ما باید مقادیر انیمیشن را با مقادیر ناشی از رویدادهای لمسی، مانند کشیدن، همگام کنیم. در مثال زیر، میبینیم که "swipe to dismiss" بهعنوان یک Modifier
(بهجای استفاده از SwipeToDismiss
) اجرا شده است. افست افقی عنصر به عنوان 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) } }
برای شما توصیه می شود
- توجه: وقتی جاوا اسکریپت خاموش است، متن پیوند نمایش داده می شود
- انیمیشن های مبتنی بر ارزش
- کشیدن، تند کشیدن، و پرت کردن
- ژست ها را درک کنید