SpringAnimation物理弹性动画

实现:

首先dynamicanimation库:

implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0'

引入viewBinding:

 viewBinding{
      enabled true
 }

布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <TextView
            android:id="@+id/spring_bt0"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_marginTop="10dp"
            android:background="@drawable/icon_qiqiu"
            android:gravity="center"
            android:paddingBottom="25dp"
            android:text="拖动"
            android:textColor="@android:color/white"
            android:textSize="18sp"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/tv1"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_marginTop="10dp"
            android:background="@drawable/icon_denglong"
            android:gravity="center"
            android:paddingBottom="25dp"
            android:text="生"
            android:textColor="#ffffff" />

        <TextView
            android:id="@+id/tv2"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_marginTop="10dp"
            android:background="@drawable/icon_denglong"
            android:gravity="center"
            android:paddingBottom="25dp"
            android:text="日"
            android:textColor="#ffffff" />

        <TextView
            android:id="@+id/tv3"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_marginTop="10dp"
            android:background="@drawable/icon_denglong"
            android:gravity="center"
            android:paddingBottom="25dp"
            android:text="快"
            android:textColor="#ffffff" />

        <TextView
            android:id="@+id/tv4"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_marginTop="10dp"
            android:background="@drawable/icon_denglong"
            android:gravity="center"
            android:paddingBottom="25dp"
            android:text="乐"
            android:textColor="#ffffff" />
    </LinearLayout>
</RelativeLayout>

添加视图:

    private PointF startPosition = new PointF();
    private VelocityTracker velocityTracker;
    private float[] remain = new float[2];
    private SpringAnimation[] springAnimationXs = new SpringAnimation[4];
    private SpringAnimation[] springAnimationYs = new SpringAnimation[4];
    private SpringAnimation springAnimationXRoot, springAnimationYRoot;
    private ActivityMainBinding binding;


        springAnimationXRoot = new SpringAnimation(binding.springBt0, DynamicAnimation.TRANSLATION_X);
        springAnimationYRoot = new SpringAnimation(binding.springBt0, DynamicAnimation.TRANSLATION_Y);
        springAnimationXs[0] = new SpringAnimation(binding.tv1, DynamicAnimation.TRANSLATION_X);
        springAnimationYs[0] = new SpringAnimation(binding.tv1, DynamicAnimation.TRANSLATION_Y);
        springAnimationXs[1] = new SpringAnimation(binding.tv2, DynamicAnimation.TRANSLATION_X);
        springAnimationYs[1] = new SpringAnimation(binding.tv2, DynamicAnimation.TRANSLATION_Y);
        springAnimationXs[2] = new SpringAnimation(binding.tv3, DynamicAnimation.TRANSLATION_X);
        springAnimationYs[2] = new SpringAnimation(binding.tv3, DynamicAnimation.TRANSLATION_Y);
        springAnimationXs[3] = new SpringAnimation(binding.tv4, DynamicAnimation.TRANSLATION_X);
        springAnimationYs[3] = new SpringAnimation(binding.tv4, DynamicAnimation.TRANSLATION_Y);

监听事件:

        springAnimationXRoot.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
            @Override
            public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
                springAnimationXs[0].animateToFinalPosition(value);
                remain[0] = springAnimationXRoot.getSpring().getFinalPosition() - value;
            }
        });

        springAnimationYRoot.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
            @Override
            public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
                springAnimationYs[0].animateToFinalPosition(value);
                remain[1] = springAnimationYRoot.getSpring().getFinalPosition() - value;
            }
        });

        for (int i = 0; i < springAnimationXs.length - 1; i++) {
            final int next = i + 1;
            springAnimationXs[i].addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
                @Override
                public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
                    springAnimationXs[next].animateToFinalPosition(value);
                }
            });
            springAnimationYs[i].addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
                @Override
                public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
                    springAnimationYs[next].animateToFinalPosition(value);
                }
            });
        }

        binding.springBt0.setOnTouchListener(this);

阻尼、钢性效果设置:

        float percent1 = 50 / 100f;//阻尼百分比
        float percent2 = 1 / 100f;//钢性百分比
        //root spring
        SpringForce springRootX = springAnimationXRoot.getSpring();
        SpringForce springRootY = springAnimationYRoot.getSpring();
        if (springRootX == null) {
            springRootX = new SpringForce();
            springAnimationXRoot.setSpring(springRootX);
        }
        if (springRootY == null) {
            springRootY = new SpringForce();
            springAnimationYRoot.setSpring(springRootY);
        }

        float highestBouncy = SpringForce.DAMPING_RATIO_HIGH_BOUNCY;
        float lowestBouncy = SpringForce.DAMPING_RATIO_NO_BOUNCY;
        float dampingRatio = (lowestBouncy - highestBouncy) * percent1;
        springRootX.setDampingRatio(dampingRatio);
        springRootY.setDampingRatio(dampingRatio);

        float highestStiffness = SpringForce.STIFFNESS_HIGH;
        float lowestStiffness = SpringForce.STIFFNESS_VERY_LOW;
        float stiffness = (highestStiffness - lowestStiffness) * percent2;
        springAnimationXRoot.getSpring().setStiffness(stiffness);
        springAnimationYRoot.getSpring().setStiffness(stiffness);

        for (int i = 0; i < springAnimationXs.length; i++) {
            SpringForce springX = springAnimationXs[i].getSpring();
            SpringForce springY = springAnimationYs[i].getSpring();
            if (springX == null) {
                springX = new SpringForce();
                springAnimationXs[i].setSpring(springX);
            }
            if (springY == null) {
                springY = new SpringForce();
                springAnimationYs[i].setSpring(springY);
            }
            springX.setDampingRatio(dampingRatio);
            springY.setDampingRatio(dampingRatio);
            springAnimationXs[i].getSpring().setStiffness(stiffness);
            springAnimationYs[i].getSpring().setStiffness(stiffness);
        }

触摸事件:

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        //滑动速度
        int index = event.getActionIndex();
        int action = event.getActionMasked();
        int pointerId = event.getPointerId(index);
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                if (velocityTracker == null) {
                    velocityTracker = VelocityTracker.obtain();
                } else {
                    velocityTracker.clear();
                }
                velocityTracker.addMovement(event);
                break;
            case MotionEvent.ACTION_MOVE:
                //跟随手指移动
                float distanceX = event.getRawX() - startPosition.x;
                float distanceY = event.getRawY() - startPosition.y;
                moveViews(distanceX, distanceY);
                //速度计算
                velocityTracker.addMovement(event);
                velocityTracker.computeCurrentVelocity(1000);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                float velocityX = velocityTracker.getXVelocity(pointerId);
                float velocityY = velocityTracker.getYVelocity(pointerId);

                startSpringAnimationWithVelocity(velocityX, velocityY);
                velocityTracker.recycle();
                velocityTracker = null;
                break;
        }
        startPosition.set(event.getRawX(), event.getRawY());
        return true;
    }

移动视图与开始弹簧动画:

 /**
     * 移动视图
     *
     * @param distanceX dx
     * @param distanceY dy
     */
    private void moveViews(float distanceX, float distanceY) {
        springAnimationXRoot.animateToFinalPosition(binding.springBt0.getTranslationX() + distanceX + remain[0]);
        springAnimationYRoot.animateToFinalPosition(binding.springBt0.getTranslationY() + distanceY + remain[1]);
    }

    /**
     * 开始弹簧动画
     *
     * @param velocityX vx
     * @param velocityY vy
     */
    public void startSpringAnimationWithVelocity(float velocityX, float velocityY) {
        springAnimationXRoot.setStartVelocity(velocityX);
        springAnimationYRoot.setStartVelocity(velocityY);
        springAnimationXRoot.animateToFinalPosition(binding.springBt0.getTranslationX() + remain[0]);
        springAnimationYRoot.animateToFinalPosition(binding.springBt0.getTranslationY() + remain[1]);
    }

完整代码:

public class MainActivity extends AppCompatActivity implements View.OnTouchListener {

    private PointF startPosition = new PointF();
    private VelocityTracker velocityTracker;
    private float[] remain = new float[2];
    private SpringAnimation[] springAnimationXs = new SpringAnimation[4];
    private SpringAnimation[] springAnimationYs = new SpringAnimation[4];
    private SpringAnimation springAnimationXRoot, springAnimationYRoot;
    private ActivityMainBinding binding;

    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        springAnimationXRoot = new SpringAnimation(binding.springBt0, DynamicAnimation.TRANSLATION_X);
        springAnimationYRoot = new SpringAnimation(binding.springBt0, DynamicAnimation.TRANSLATION_Y);
        springAnimationXs[0] = new SpringAnimation(binding.tv1, DynamicAnimation.TRANSLATION_X);
        springAnimationYs[0] = new SpringAnimation(binding.tv1, DynamicAnimation.TRANSLATION_Y);
        springAnimationXs[1] = new SpringAnimation(binding.tv2, DynamicAnimation.TRANSLATION_X);
        springAnimationYs[1] = new SpringAnimation(binding.tv2, DynamicAnimation.TRANSLATION_Y);
        springAnimationXs[2] = new SpringAnimation(binding.tv3, DynamicAnimation.TRANSLATION_X);
        springAnimationYs[2] = new SpringAnimation(binding.tv3, DynamicAnimation.TRANSLATION_Y);
        springAnimationXs[3] = new SpringAnimation(binding.tv4, DynamicAnimation.TRANSLATION_X);
        springAnimationYs[3] = new SpringAnimation(binding.tv4, DynamicAnimation.TRANSLATION_Y);

        springAnimationXRoot.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
            @Override
            public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
                springAnimationXs[0].animateToFinalPosition(value);
                remain[0] = springAnimationXRoot.getSpring().getFinalPosition() - value;
            }
        });

        springAnimationYRoot.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
            @Override
            public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
                springAnimationYs[0].animateToFinalPosition(value);
                remain[1] = springAnimationYRoot.getSpring().getFinalPosition() - value;
            }
        });

        for (int i = 0; i < springAnimationXs.length - 1; i++) {
            final int next = i + 1;
            springAnimationXs[i].addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
                @Override
                public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
                    springAnimationXs[next].animateToFinalPosition(value);
                }
            });
            springAnimationYs[i].addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
                @Override
                public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
                    springAnimationYs[next].animateToFinalPosition(value);
                }
            });
        }

        binding.springBt0.setOnTouchListener(this);

        float percent1 = 50 / 100f;//阻尼百分比
        float percent2 = 1 / 100f;//钢性百分比
        //root spring
        SpringForce springRootX = springAnimationXRoot.getSpring();
        SpringForce springRootY = springAnimationYRoot.getSpring();
        if (springRootX == null) {
            springRootX = new SpringForce();
            springAnimationXRoot.setSpring(springRootX);
        }
        if (springRootY == null) {
            springRootY = new SpringForce();
            springAnimationYRoot.setSpring(springRootY);
        }

        float highestBouncy = SpringForce.DAMPING_RATIO_HIGH_BOUNCY;
        float lowestBouncy = SpringForce.DAMPING_RATIO_NO_BOUNCY;
        float dampingRatio = (lowestBouncy - highestBouncy) * percent1;
        springRootX.setDampingRatio(dampingRatio);
        springRootY.setDampingRatio(dampingRatio);

        float highestStiffness = SpringForce.STIFFNESS_HIGH;
        float lowestStiffness = SpringForce.STIFFNESS_VERY_LOW;
        float stiffness = (highestStiffness - lowestStiffness) * percent2;
        springAnimationXRoot.getSpring().setStiffness(stiffness);
        springAnimationYRoot.getSpring().setStiffness(stiffness);

        for (int i = 0; i < springAnimationXs.length; i++) {
            SpringForce springX = springAnimationXs[i].getSpring();
            SpringForce springY = springAnimationYs[i].getSpring();
            if (springX == null) {
                springX = new SpringForce();
                springAnimationXs[i].setSpring(springX);
            }
            if (springY == null) {
                springY = new SpringForce();
                springAnimationYs[i].setSpring(springY);
            }
            springX.setDampingRatio(dampingRatio);
            springY.setDampingRatio(dampingRatio);
            springAnimationXs[i].getSpring().setStiffness(stiffness);
            springAnimationYs[i].getSpring().setStiffness(stiffness);
        }

        binding.tv1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "生日快乐", Toast.LENGTH_SHORT).show();
            }
        });
    }

    /**
     * 移动视图
     *
     * @param distanceX dx
     * @param distanceY dy
     */
    private void moveViews(float distanceX, float distanceY) {
        springAnimationXRoot.animateToFinalPosition(binding.springBt0.getTranslationX() + distanceX + remain[0]);
        springAnimationYRoot.animateToFinalPosition(binding.springBt0.getTranslationY() + distanceY + remain[1]);
    }

    /**
     * 开始弹簧动画
     *
     * @param velocityX vx
     * @param velocityY vy
     */
    public void startSpringAnimationWithVelocity(float velocityX, float velocityY) {
        springAnimationXRoot.setStartVelocity(velocityX);
        springAnimationYRoot.setStartVelocity(velocityY);
        springAnimationXRoot.animateToFinalPosition(binding.springBt0.getTranslationX() + remain[0]);
        springAnimationYRoot.animateToFinalPosition(binding.springBt0.getTranslationY() + remain[1]);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        //滑动速度
        int index = event.getActionIndex();
        int action = event.getActionMasked();
        int pointerId = event.getPointerId(index);
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                if (velocityTracker == null) {
                    velocityTracker = VelocityTracker.obtain();
                } else {
                    velocityTracker.clear();
                }
                velocityTracker.addMovement(event);
                break;
            case MotionEvent.ACTION_MOVE:
                //跟随手指移动
                float distanceX = event.getRawX() - startPosition.x;
                float distanceY = event.getRawY() - startPosition.y;
                moveViews(distanceX, distanceY);
                //速度计算
                velocityTracker.addMovement(event);
                velocityTracker.computeCurrentVelocity(1000);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                float velocityX = velocityTracker.getXVelocity(pointerId);
                float velocityY = velocityTracker.getYVelocity(pointerId);

                startSpringAnimationWithVelocity(velocityX, velocityY);
                velocityTracker.recycle();
                velocityTracker = null;
                break;
        }
        startPosition.set(event.getRawX(), event.getRawY());
        return true;
    }
}

图片资源自行下载:https://www.iconfont.cn/

猜你喜欢

转载自blog.csdn.net/juer2017/article/details/118525595