You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何创建手势效果动画?Android Studio中Java实现扫动动画方法

关于手势扫动动画的实现方案

Hey there! Let's break down your two questions clearly, since I've implemented similar swipe-based animations in Android projects before.


问题1:如何创建这类手势扫动动画效果?

这类动画的核心是跟随用户手势的实时位移+手势结束后的补间动画,核心逻辑可以拆成这几步:

  • 首先要监听用户的触摸/手势事件,获取手指的起始位置、移动轨迹和结束时的速度
  • 在手势移动过程中,实时更新目标视图的位置(用translationX/translationY属性比直接修改布局参数更流畅,因为是基于视图自身的偏移,不会触发重布局)
  • 手势结束时,根据滑动的距离和速度判断是触发目标动作(比如滑出屏幕)还是回弹到初始位置
  • 给动画添加合适的插值器(比如AccelerateDecelerateInterpolator),让动效更贴近真实物理反馈,避免生硬的移动

问题2:Android Studio中用Java实现扫动动画

下面是一个完整的可运行示例,实现类似参考效果的卡片扫动:

第一步:准备布局文件

res/layout/activity_main.xml中添加可滑动的卡片:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/swipe_card"
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:layout_centerVertical="true"
        android:background="#f5f5f5"
        android:gravity="center"
        android:orientation="vertical"
        android:elevation="4dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="向左/向右扫动我"
            android:textSize="18sp" />
    </LinearLayout>

</RelativeLayout>

第二步:Java代码实现手势监听与动画

MainActivity.java中,我们用GestureDetector来处理手势事件,同时实时更新卡片位置:

import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.LinearLayout;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener {

    private GestureDetector gestureDetector;
    private LinearLayout swipeCard;
    private float initialTouchX;
    // 判定为有效滑动的最小距离(可根据需求调整)
    private static final int SWIPE_MIN_DISTANCE = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        swipeCard = findViewById(R.id.swipe_card);
        gestureDetector = new GestureDetector(this, this);

        // 给卡片设置触摸监听,传递事件给GestureDetector
        swipeCard.setOnTouchListener((v, event) -> {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    // 记录手指按下时的X坐标
                    initialTouchX = event.getRawX();
                    break;
                case MotionEvent.ACTION_MOVE:
                    // 实时计算位移,更新卡片位置
                    float deltaX = event.getRawX() - initialTouchX;
                    swipeCard.setTranslationX(deltaX);
                    break;
            }
            // 让GestureDetector处理后续手势事件
            return gestureDetector.onTouchEvent(event);
        });
    }

    @Override
    public boolean onDown(MotionEvent e) {
        // 必须返回true,否则后续手势事件不会被触发
        return true;
    }

    @Override
    public void onShowPress(MotionEvent e) {}

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {}

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        float swipeDistance = e2.getRawX() - e1.getRawX();

        // 判断滑动距离是否达到阈值
        if (Math.abs(swipeDistance) > SWIPE_MIN_DISTANCE) {
            if (swipeDistance > 0) {
                // 向右滑动:回弹到初始位置
                resetCardPosition();
            } else {
                // 向左滑动:滑出屏幕后重置位置
                swipeCard.animate()
                        .translationX(-swipeCard.getWidth())
                        .setInterpolator(new AccelerateDecelerateInterpolator())
                        .setDuration(300)
                        .withEndAction(this::resetCardPosition);
            }
            return true;
        } else {
            // 滑动距离不足,回弹
            resetCardPosition();
            return true;
        }
    }

    // 重置卡片到初始位置的动画
    private void resetCardPosition() {
        swipeCard.animate()
                .translationX(0)
                .setInterpolator(new AccelerateDecelerateInterpolator())
                .setDuration(200)
                .start();
    }
}

额外优化建议

  • 如果需要添加更多动效(比如缩放、透明度变化),可以在animate()中链式调用scaleX()alpha()等方法
  • 要是想实现多页面的滑动切换,可以用ViewPager2配合自定义PageTransformer,但单视图扫动用上面的方案更轻量
  • 可以根据需求调整SWIPE_MIN_DISTANCE和动画时长,让效果更符合你的预期

内容的提问来源于stack exchange,提问作者Kunal Khan

火山引擎 最新活动