AndroidTVWidget框架
在此框架上封装了几个类用于快速实现焦点动画。
使用AndroidTVWidget完成运动焦点框效果。
- 尽可能减少布局层级。
- 需获取焦点的view最好在同一层级上。
- 焦点框要处于最上层,避免遮盖。
- 注意view的边距,防止view放大时显示不全。
以下展示几种不同布局环境下对焦点框的处理:重点是获取到view的焦点并对焦点得失两种状态分别处理。
Demo地址
在布局中添加MainUpView,使MainUpView处于布局的上层。
设置焦点框:
private void initMoveBridge() {
float density = getResources().getDisplayMetrics().density;
mEffectNoDrawBridge = new EffectNoDrawBridge();
mainUpView.setEffectBridge(mEffectNoDrawBridge);
mEffectNoDrawBridge.setUpRectResource(R.drawable.white_light); // 设置移动边框图片.
RectF rectF = new RectF(15 * density, 15 * density, 14 * density, 15 * density);
mEffectNoDrawBridge.setDrawUpRectPadding(rectF);
}
对view添加监听:
private void initListener(){
cardView1.setOnFocusChangeListener(this);
cardView2.setOnFocusChangeListener(this);
cardView3.setOnFocusChangeListener(this);
cardView4.setOnFocusChangeListener(this);
cardView5.setOnFocusChangeListener(this);
cardView6.setOnFocusChangeListener(this);
cardView7.setOnFocusChangeListener(this);
cardView8.setOnFocusChangeListener(this);
cardView9.setOnFocusChangeListener(this);
}
处理:
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
mOldView = v;
mEffectNoDrawBridge.setVisibleWidget(false);
//可以对某个view进行特殊处理
// if (v.getId()==R.id.card_img) {
// mEffectNoDrawBridge.setFocusView(v, 1.05f);
// } else {
// mEffectNoDrawBridge.setFocusView(v, 1.15f);
// }
mEffectNoDrawBridge.setFocusView(v, 1.15f);
v.bringToFront();
} else {
mEffectNoDrawBridge.setUnFocusView(mOldView);
mEffectNoDrawBridge.setVisibleWidget(true);
}
}
详情见Demo中的MainActivity。
另一种方式:
private void initFocusTree(){
rootView.getViewTreeObserver().addOnGlobalFocusChangeListener(new ViewTreeObserver.OnGlobalFocusChangeListener() {
@Override
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
if (newFocus != null ) {
//可以在此对newFocus进行过滤,可以使一些view不能获取焦点或者展示不同的样式。
mEffectNoDrawBridge.setVisibleWidget(false);
mNewFocus = newFocus;
mOldView = oldFocus;
mainUpView.setFocusView(newFocus, oldFocus, 1.2f);
newFocus.bringToFront();
} else { // 标题栏处理.
mNewFocus = null;
mOldView = null;
mainUpView.setUnFocusView(oldFocus);
mEffectNoDrawBridge.setVisibleWidget(true);
}
}
});
}
不同应用场景中的封装类:
MainUpViewActivity
- 适合含有View,不包含ViewGroup的布局。
- 使用简单方便。
- 创建Activity继承MainUpViewActivity
- 在onCreate方法中调用init方法初始化
- 不需要在布局中添加MainUpView控件
如下:
public class Example1Activity extends MainUpViewActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//参数分别为边框图片,左上右下的边距,根据需求自行调整
init(R.drawable.white_light,12,12,12,12);
}
}
若要使一些view不能获取焦点或者展示不同的样式。可重写initFocusTree();
详情见Demo中的Example1Activity。
BaseActivity
用于处理activity中RecyclerViewTV的焦点框,RecyclerViewTV是AndroidTVWidget中为Android TV开发自定义的控件,使用RecyclerViewTV代替RecyclerView。 BaseActivity是一个抽象类,只需实现几个固定的方法即可。
public class Example2Activity extends BaseActivity {
@Override
public int getLayout() {
//布局xml
return 0;
}
@Override
public void initView() {
init(...);//初始化焦点框
//初始化布局
}
@Override
public void loadData() {
//数据加载
}
@Override
public RecyclerView.LayoutManager getLayoutManager() {
//RecyclerView的LayoutManager类型
return null;
}
@Override
public RecyclerView.Adapter getAdapter() {
//适配器
return null;
}
@Override
public void onItemClick(View itemView, int position) {
//item的点击事件
}
@Override
public void onItemSelected(View itemView, int position) {
//选中item
}
@Override
public void onItemUnSelected(View itemView, int position) {
//失去选中item
}
}
setAutoFocus(false);//默认为true,第一项获取焦点;为false,不自动获取焦点。
setAnimScale(1.2f);//设置焦点放大的倍数,默认为1.2倍。
当前BaseActivity实现类中的其他view,可以通过setOnFocusListener()来监听焦点并实现动画。详情请见,Demo中的Example2Activity。
BaseFragment
RecyclerViewTV在Fragment中,与BaseActivity类似。
见Demo中Example3Fragment。
public class Example3Fragment extends BaseFragment {
private RecyclerViewTV recyclerViewTV;
private MainUpView mainUpView;
private List<String> list=new ArrayList<>();
private ExamAdapter examAdapter;
@Override
public int getLayout() {
return 0;
}
@Override
public void initView(View view) {
}
@Override
public void loadData() {
}
@Override
public void onItemClick(View itemView, int position) {
}
@Override
public void onItemSelected(View itemView, int position) {
}
@Override
public void unItemSelected(View itemView, int position) {
}
@Override
public RecyclerView.Adapter getAdapter() {
return null;
}
@Override
public RecyclerView.LayoutManager getLayoutManager() {
return null;
}
}