TV 按钮到达边缘后的抖动效果 (listview,gridview匹配一下)

本文为转载,原文地址----
 /*———————————————— 原文链接:https://blog.csdn.net/haibaramo/article/details/79992901*/


/*
* 焦点到达边缘后的抖动效果
*
* */
public class ShakeAnimatorUtil {
    private View oldViewX, oldViewY;
    public static final int HORIZONTAL_FLAG = 0;
    public static final int VERTICAL_FLAG = 1;

    public void bindShakeAnimator(View newView, KeyEvent keyEvent) {
        if (newView != null && isNeedShake(newView, keyEvent)) {  //判断是否可以抖动
            if (getDirectorFlag(keyEvent) == HORIZONTAL_FLAG) {  //抖动方向应为横向
                if (oldViewX == null || (oldViewX != null && oldViewX != newView)) {
                    //是一个新的未曾设置动画的view,设置属性动画
                    setHorizontalShakeAnimator(newView);
                }
                startHorizontalShakeAnimator();
                oldViewX = newView;
            } else if (getDirectorFlag(keyEvent) == VERTICAL_FLAG) {  //纵向同上
                if (oldViewY == null || (oldViewY != null && oldViewY != newView)) {
                    setVerticalShakeAnimator(newView);
                }
                startVerticalShakeAnimator();
                oldViewY = newView;
            }
        }
    }

    //判断是哪个方向
    private int getDirectorFlag(KeyEvent keyEvent) {
        switch (keyEvent.getKeyCode()) {
            case KeyEvent.KEYCODE_DPAD_LEFT:
            case KeyEvent.KEYCODE_DPAD_RIGHT:
                return HORIZONTAL_FLAG;
            case KeyEvent.KEYCODE_DPAD_UP:
            case KeyEvent.KEYCODE_DPAD_DOWN:
                return VERTICAL_FLAG;
        }
        return -1;
    }

    //需要传入焦点所在的view,以及当前的keyEvent
    private boolean isNeedShake(View itemView, KeyEvent event) {
        switch (event.getKeyCode()) {
            case KeyEvent.KEYCODE_DPAD_LEFT:
                //当按下左键时,调用focusSearch方法获得左方向上是否还有下一个可以获得焦点的view
                //若有,则不需要抖动,若无,需要抖动
                if (null == itemView.focusSearch(View.FOCUS_LEFT)) {
                    return true;
                }
                break;
            case KeyEvent.KEYCODE_DPAD_RIGHT:
                if (null == itemView.focusSearch(View.FOCUS_RIGHT)) {
                    return true;
                }
                break;
            case KeyEvent.KEYCODE_DPAD_UP:
                if (null == itemView.focusSearch(View.FOCUS_UP)) {
                    return true;
                }
                break;
            case KeyEvent.KEYCODE_DPAD_DOWN:
                if (null == itemView.focusSearch(View.FOCUS_DOWN)) {
                    return true;
                }
                break;
        }
        return false;
    }
    //定义一个横向抖动的动画
    private ObjectAnimator translationAnimatorX,translationAnimatorY;
    private static final int DURATION = 400;

    private void setHorizontalShakeAnimator(View newView) {
        //动画种类:X轴平移,后面的值为移动参数,正值为右,负值为左(Y轴正值为下,负值为上)
        translationAnimatorX = ObjectAnimator.ofFloat(newView, "translationX", 0f, 5f, 0f, -5f, 0f, 5f, 0f, -5f, 0f);
        //用于控制动画快慢节奏,此处使用系统自带的线性Interpolator(匀速),此外还有各种变速Interpolator
        translationAnimatorX.setInterpolator(new LinearInterpolator());
        //设置动画重复次数,ValueAnimator.INFINITE即-1表示用于一直重复
        translationAnimatorX.setRepeatCount(ValueAnimator.INFINITE);
        translationAnimatorX.setDuration(DURATION);
    }

    private void setVerticalShakeAnimator(View newView) {
        //动画种类:X轴平移,后面的值为移动参数,正值为右,负值为左(Y轴正值为下,负值为上)
        translationAnimatorY = ObjectAnimator.ofFloat(newView, "translationY", 0f, 5f, 0f, -5f, 0f, 5f, 0f, -5f, 0f);
        //用于控制动画快慢节奏,此处使用系统自带的线性Interpolator(匀速),此外还有各种变速Interpolator
        translationAnimatorY.setInterpolator(new LinearInterpolator());
        //设置动画重复次数,ValueAnimator.INFINITE即-1表示用于一直重复
        translationAnimatorY.setRepeatCount(ValueAnimator.INFINITE);
        translationAnimatorY.setDuration(DURATION);
    }

    private void startHorizontalShakeAnimator() {
        //此处判断动画是否已经在run,若是则不重新调用start方法,避免重复触发导致抖动的不流畅
        if (translationAnimatorX != null && !translationAnimatorX.isRunning()) {
            //结束纵向动画,非本身横向动画
            endVerticalAnimator();
            translationAnimatorX.setRepeatCount(ValueAnimator.INFINITE);
            translationAnimatorX.start();
        }
    }
    private void startVerticalShakeAnimator() {
        //此处判断动画是否已经在run,若是则不重新调用start方法,避免重复触发导致抖动的不流畅
        if (translationAnimatorY != null && !translationAnimatorY.isRunning()) {
            //结束纵向动画,非本身横向动画
            endHorizontalAnimator();
            translationAnimatorY.setRepeatCount(ValueAnimator.INFINITE);
            translationAnimatorY.start();
        }
    }

    private void endVerticalAnimator() {
        if (translationAnimatorY != null) {
            //结束纵向动画,调用end()动画会到动画周期的最后一帧然后停止,调用cancel()动画会停止时间轴,停止在中间状态
            translationAnimatorY.end();
        }
    }
    private void endHorizontalAnimator() {
        if (translationAnimatorX != null) {
            //结束纵向动画,调用end()动画会到动画周期的最后一帧然后停止,调用cancel()动画会停止时间轴,停止在中间状态
            translationAnimatorX.end();
        }
    }

    //当按键抬起时,使动画只执行完当前周期,便自动结束
    public void completeOneShakeCycle() {
        if (translationAnimatorX != null && translationAnimatorX.isRunning()) {
            //修改动画的重复次数为0,即只执行1次
            translationAnimatorX.setRepeatCount(0);
        }
        if (translationAnimatorY != null && translationAnimatorY.isRunning()) {
            translationAnimatorY.setRepeatCount(0);
        }
    }

    public void endShakeAnimator() {
        endHorizontalAnimator();  //调用end()即可,具体方法略
        endVerticalAnimator();
    }
    public void cancelAllShakeAnimator() {
        if (translationAnimatorX != null) {
            translationAnimatorX.cancel();
        }
        if (translationAnimatorY != null) {
            translationAnimatorY.cancel();
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值