适用于android智能电视的全局焦点框控件,可以省去为每个按钮设计focused的按钮图标。

效果描述:

1.完整适配各种尺寸的图标按钮

2.平滑的补件动画切换焦点

3.点击效果闪光+声音

import android.content.Context;import android.graphics.drawable.AnimationDrawable;import android.media.AudioManager;import android.media.SoundPool;import android.os.Handler;import android.util.AttributeSet;import android.util.Log;import android.view.View;import android.view.animation.Animation;import android.view.animation.Animation.AnimationListener;import android.view.animation.AnimationSet;import android.view.animation.ScaleAnimation;import android.view.animation.TranslateAnimation;import android.widget.ImageView;/** * 焦点框控件 * @author jiangyuchen * @date 2014-2-13 */public class BorderView extends ImageView implements AnimationListener {protected static final String TAG = "BestSetting.BorderView";private static int BORDER_SIZE = 20;private static int TRAN_DUR_ANIM = 250;private SoundPool sp;private Context mContext;public BorderView(Context context, AttributeSet attrs) {super(context, attrs);mContext = context;}/** * 设置边界框的外框大小 * @param padding */public void setBorderSize(int size){BORDER_SIZE = size;}/** * 设置位移动画时间 * @param dur */public void setTranslateAnimtionDuration(int dur){TRAN_DUR_ANIM = dur;}public void setLocation(View view){ViewLocation location = findLocationWithView(view);//Log.v(TAG, "setLocation X:"+location.x+" Y:"+location.y);mLeft = location.x-(int)BORDER_SIZE;mTop = location.y-(int)BORDER_SIZE;mRight = location.x+(int)BORDER_SIZE+view.getWidth();mBottom = location.y+(int)BORDER_SIZE+view.getHeight();this.layout(mLeft, mTop, mRight, mBottom);this.clearAnimation();BorderView.this.setVisibility(View.VISIBLE);}private int mLeft, mTop, mRight, mBottom;@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {super.onLayout(changed, left, top, right, bottom);if(this.mLeft != left || mTop != top || mRight != right || mBottom != bottom){this.layout(this.mLeft, this.mTop, this.mRight, this.mBottom);}}/** * 获取View的位置 * @param view 获取的控件 * @return 位置 */public ViewLocation findLocationWithView(View view){int[] location = new int[2];view.getLocationOnScreen(location);    return new ViewLocation(location[0], location[1]);}private AnimationDrawable  mBoxBgAnim;/** * 初始化焦点框动画 */public void runBorderAnimation(){this.setBackgroundResource(R.anim.box_normal);restartBoxAnim();}/** * 重启闪烁动画 * @param context */public void restartBoxAnim(){BorderView.this.setVisibility(View.VISIBLE);this.clearAnimation();if(mBoxBgAnim == null){mBoxBgAnim = (AnimationDrawable) this.getBackground(); }if(mBoxBgAnim.isRunning()){mBoxBgAnim.stop();}mBoxBgAnim.start();this.startAnimation(AnimUtils.buildAnimBoxNormal(mContext));}/** * 记录上一次的焦点组件,用于判断是否未移动控件的焦点,相同则不重新加载动画 */private View mLastFocusView;/** * 启动焦点框位移动画 */public void runTranslateAnimation(View toView) {runBorderAnimation();if(toView == null || mLastFocusView == toView){return;}//缩放比例float scaleWValue =  (float) this.getWidth()/((float) toView.getWidth()+2*BORDER_SIZE);float scaleHValue =  (float) this.getHeight()/((float) toView.getHeight()+2*BORDER_SIZE);ScaleAnimation scale = new ScaleAnimation( scaleWValue, 1.0f,scaleHValue,1.0f);//记录位置信息,以为启动动画前box已经设置到目标位置了。ViewLocation fromLocation = findLocationWithView(this);ViewLocation toLocation = findLocationWithView(toView);TranslateAnimation tran = new TranslateAnimation(-toLocation.x+(float)BORDER_SIZE+fromLocation.x, 0,-toLocation.y+(float)BORDER_SIZE+fromLocation.y, 0);//Log.v("TAG","fromX:"+(-toLocation.x+(float)BORDER_SIZE+fromLocation.x)+" fromY:"+(-toLocation.y+(float)BORDER_SIZE+fromLocation.y));//Log.v("TAG","fromX:"+fromLocation.x+ " toX:" +toLocation.x+" fromY:"+fromLocation.y+" toY:"+toLocation.x);//TranslateAnimation tran = new TranslateAnimation(0, toLocation.x-(float)BORDER_SIZE-fromLocation.x,//0, toLocation.y-(float)BORDER_SIZE-fromLocation.y);AnimationSet boxAnimaSet = new AnimationSet(true);boxAnimaSet.setAnimationListener(this);boxAnimaSet.addAnimation(scale);boxAnimaSet.addAnimation(tran);boxAnimaSet.setDuration(TRAN_DUR_ANIM);BorderView.this.setVisibility(View.INVISIBLE);setLocation(toView);//先位移到目标位置再启动动画Log.v(TAG, "setLocation runTranslateAnimation");BorderView.this.startAnimation(boxAnimaSet);mLastFocusView = toView;}public void playClickOgg(){if(sp == null){sp =new SoundPool(1, AudioManager.STREAM_MUSIC, 0);sp.load(mContext, R.raw.djtx, 0);}sp.play(1, 1, 1, 0, 0, 1);}private  static AnimationSet mBoxAnimClick;private void runClickAnimtion(){playClickOgg();if(mBoxAnimClick == null){mBoxAnimClick = AnimUtils.buildAnimBoxClick(mContext);}BorderView.this.startAnimation(mBoxAnimClick);notifyRestartBoxAnim(500);}public static final int MSG_BOX_BG_ANIM = 10;public static final int MSG_BOX_CLICK_ANIM = 11;/** * 重启背景动画 * @param delay 延迟时间毫秒 */void notifyRestartBoxAnim(int delay){mBoxHandler.sendEmptyMessageDelayed(MSG_BOX_BG_ANIM, delay);}/** * 点击动画 */public void notifyClickBoxAnim(){mBoxHandler.sendEmptyMessageDelayed(MSG_BOX_CLICK_ANIM, 10);}Handler mBoxHandler = new Handler(){public void handleMessage(android.os.Message msg) {switch(msg.what){case MSG_BOX_BG_ANIM:restartBoxAnim();break;case MSG_BOX_CLICK_ANIM:runClickAnimtion();break;}};};@Overridepublic void onAnimationEnd(Animation arg0) {notifyRestartBoxAnim(0);}@Overridepublic void onAnimationRepeat(Animation arg0) {}@Overridepublic void onAnimationStart(Animation arg0) {}}
  
动画类:
  
import android.content.Context;import android.util.Log;import android.view.animation.AlphaAnimation;import android.view.animation.Animation;import android.view.animation.AnimationSet;import android.view.animation.ScaleAnimation;public class AnimUtils {private static final String TAG = "AnimUtils";private static Animation mBoxAnimNormal;public static Animation buildAnimBoxNormal(Context context) {if (mBoxAnimNormal != null) {return mBoxAnimNormal;}mBoxAnimNormal = android.view.animation.AnimationUtils.loadAnimation(context, R.anim.box_alpha);return mBoxAnimNormal;}public static AnimationSet buildAnimBoxClick(Context context) {final ScaleAnimation scale = new ScaleAnimation(0.5f, 1.3f, 0.5f, 1.3f,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);AlphaAnimation alpha = new AlphaAnimation(0.5f, 1.0f);AnimationSet mBoxAnimClick = new AnimationSet(true);mBoxAnimClick.addAnimation(scale);mBoxAnimClick.addAnimation(alpha);mBoxAnimClick.setDuration(100);return mBoxAnimClick;}}


动画xml:

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"     >    <alpha        android:repeatCount="infinite"        android:repeatMode="restart"        android:duration="1000"        android:fromAlpha="2.0"        android:toAlpha="0.1" />    <alpha         android:repeatCount="infinite"        android:repeatMode="restart"        android:duration="1000"        android:fromAlpha="0.1"        android:toAlpha="2.0" /></set>


<?xml version="1.0" encoding="utf-8"?><animation-list xmlns:android="http://schemas.android.com/apk/res/android"    android:oneshot="false" >    <item        android:drawable="@drawable/bound"        android:duration="1000"/>    <item        android:drawable="@drawable/bound2"        android:duration="1000"/></animation-list>


bound:Android发光特效焦点框-遥控器版本_第1张图片

bound2:

加入到布局中方法:

父布局使用相对布局

<com.bestv.setting.views.BorderView    android:layout_width="0px"    android:layout_height="0px"    android:id="@+id/box"    />

在Acitivity中的使用方法:

import android.app.Activity;import android.os.Handler;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnFocusChangeListener;import com.bestv.setting.utils.BoxNotFoundException;import com.bestv.setting.views.BorderView;public class BaseActivity extends Activity implements OnFocusChangeListener {private static final String TAG_base = "BaseActivity";BorderView mBorderView;Handler mHandler = new Handler();@Overrideprotected void onStart() {super.onStart();View view = findViewById(R.id.box);if(view == null){throw new BoxNotFoundException();//必须在父布局中焦点框控件,否则抛出异常}}public BorderView getBorderView() {return mBorderView;}public void setBorderView(BorderView box) {this.mBorderView = box;}public void setFocusedView(final View view, int delay){if(mBorderView == null){mBorderView = (BorderView)findViewById(R.id.box);}mBorderView.runBorderAnimation();mHandler.postDelayed(new Runnable() {@Overridepublic void run() {if(view == null){return;}view.requestFocus();mBorderView.setLocation(view);}}, delay);}public void runClickAnim(){this.getBorderView().notifyClickBoxAnim();}@Overrideprotected void onResume() {super.onResume();}@Overridepublic void onFocusChange(View v, boolean hasFocus) {if(hasFocus){mBorderView.runTranslateAnimation(v);}}public void setClickListener(View v, OnClickListener listener){v.setOnClickListener(listener);v.setOnFocusChangeListener(this);}}


为每个能够获取到焦点的空间调用函数:

setClickListener(View v, OnClickListener listener)

至此全部完成。

更多相关文章

  1. Activity 转场动画踩坑
  2. Android中的四种动画效果
  3. 两个Android开源项目:Android显示GIF动画
  4. Android动画之view动画
  5. 捋一捋Android的转场动画
  6. Android Activity 界面切换动画
  7. Android Studio 初步在代码中操作控件

随机推荐

  1. Error generating final archive: Debug
  2. Android(安卓)获取WebView的高度
  3. 在Android中怎么增加一个类似于framework
  4. Android(安卓)java.lang.StackOverflowEr
  5. Android(安卓)编译命令及选项
  6. NDK DEBUG方法
  7. Android课程---Android(安卓)Studio的一
  8. 如何在MSM中实现Android震动系统
  9. Android开发之异步详解(二)之AsyncTask
  10. setContentView( )方法