/*
———————————————— 原文链接: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();
}
}
}