tv 焦点到达边缘后的抖动效果 listview gridview转移一下焦点

/*

 

———————————————— 原文链接:https://blog.csdn.net/haibaramo/article/details/79992901*/

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if(util == null){
            util = new ShakeAnimatorUtil();
        }
        View view = getCurrentFocus();
        if(view instanceof GridView){
            util.bindShakeAnimator(((GridView) view).getSelectedView(),event);
        }else if(view instanceof ListView){
            util.bindShakeAnimator(((ListView) view).getSelectedView(),event);
        }else{
            util.bindShakeAnimator(getCurrentFocus(), event);
        }
​
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        /*
         * 按钮颤动
         * */
      if(util != null){
            util.completeOneShakeCycle();
        }
        return super.onKeyUp(keyCode, event);
    }

​

/*
* 焦点到达边缘后的抖动效果
*
* */
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();
        }
    }
 
}

 

 

你可能感兴趣的:(android)