前一篇我们已经讲解的基本Android TV 开发的基础技能Android TV开发经验总结---初识TV开发,接下来聊聊TV开发中所涉及到的控件运用
目前Android TV 开发的资料不是蛮多,经过一系列的搜索,目前比较适用的框架推荐
冰雪情缘TV / Android-TV-Frame 项目地址:https://git.oschina.net/hailongqiu/AndroidTVWidget
在我们TV开发中用到最多的可能就是网格和列表了,今天我们先讲讲GridView,有人就会想现在不都是在用recyclerview吗? 但是我告诉你,在TV开发中目前如果不使用google自己的LeackbackTV框架的话目前的原生recyclerview在开发中你会发现,上下左右快速滑动的时候焦点不能预期的达到效果,当然后面我会讲解recyclerview在开发过程中的使用
系统中的原生GridView在开发过程中会出现哪些问题呢,我们又可以怎么解决?
首先为了让GridView能够上下左右焦点位置不乱跑,我使用的是Androd-tv-frame中的GridViewTV控件,具体代码请看上面连接中的源码
然后在使用GridView过程中一般需要用到的监听事件
gridView.setOnItemSelectedListener 选中事件
//选中事件
gridView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){
@Override
public void onItemSelected (AdapterView < ? > parent, View view,int position, long id){
curposition = position;
}
@Override public void onNothingSelected (AdapterView < ? > parent){
}
});
//点击事件
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
@Override public void onItemClick (AdapterView < ? > parent, View view,int position, long id){
}
});
//是否获取焦点事件
gridView.setOnFocusChangeListener(new View.OnFocusChangeListener(){
@Override public void onFocusChange (View view,boolean b){
}
});
此处需要特别说明的是 gridView.setFocusable(true); 改变控件是否可以获得焦点,然而同时会触发 setOnFocusChangeListener事件
在GridView开发过程中还有很坑爹的问题,GridView在初始化或者重新setAdapter后在4.3版本以上会抢焦点默认选中第一个Item ,不光是GridView listview也是如此的情况,所以要避免这种情况的话需要给gridView.setFocusable(false)使得gridview不能抢焦
其实在开发中如果在4.3版本一下你需要默认第一个Item也是有方法的,可以看看
/**
* 判断当前选中的位置在屏幕中的相对位置
*
* @param
* @return
*/
public static final int LEFT = 0;
public static final int RIGHT = 1;
public static final int BOTTOM = 2;
public static final int TOP = 3;
public int getGridSelectionState() {
int selection = gridView.getSelectedItemPosition();
int total = mLiveData.size();
if (total <= 0) {
return -1;
}
if(selection= total) {
return BOTTOM;
}
if (selection % gridView.getNumColumns() == 0) {
return LEFT;
} else if (selection % gridView.getNumColumns() == gridView.getNumColumns()-1) {
return RIGHT;
} else {
return -1;
}
}
如果这时候你还需要通过方向来确定的话可以使用如下代码
private int direction = -1;
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_LEFT:
direction = 1;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
direction = 2;
break;
case KeyEvent.KEYCODE_DPAD_UP:
direction = 3;
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
direction = 4;
break;
default:
direction = -1;
break;
}
return super.dispatchKeyEvent(event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_DOWN:
if (isGridFoucse) { //
接着可能就是选中放大的效果了,之前我一直使用的还是上面框架中的放大效果,移动放大框效果很给力,只是在过程中你特别需要注意设置两个属性
android:clipToPadding="false" android:clipChildren="false" 具体有什么用处你可以问问度娘,会解释的很清楚。
但是由于后期配合项目整体UI的要求,框架不适合,那么又如何有放大选中的效果呢,我的思路是设置Item放大后的背景,先隐藏当选中的时候对View进行放大正好是背景的大小,这就需要我们自己计算Item的宽高了,给个我实现的案例
先看看xml
gridView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view,
int position, long id) {
if (isGridFoucse && view != null) {
if (mOldView != null) {
LiveGridAdapter.ViewHolder oldholder = (LiveGridAdapter.ViewHolder) mOldView.getTag();
setGridBg(oldholder,false);
}
if (view != null) {
LiveGridAdapter.ViewHolder holder = (LiveGridAdapter.ViewHolder) view.getTag();
view.bringToFront();
setGridBg(holder, true);
}
mOldView = view;
curposition = position;
}
}
@Override
public void onNothingSelected(AdapterView> parent) {
}
});
private void setGridBg(final LiveGridAdapter.ViewHolder oldholder,boolean toBig){
if(toBig){
oldholder.root_layout.animate().scaleX(1.09f).scaleY(1.09f).setDuration(DEFAULT_TRAN_DUR_ANIM)
.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
if (oldholder.grid_border != null) {
oldholder.grid_border.setVisibility(View.VISIBLE);
}
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}else{
oldholder.root_layout.animate().scaleX(1.0f).scaleY(1.0f).setDuration(DEFAULT_TRAN_DUR_ANIM)
.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
if (oldholder.grid_border != null) {
oldholder.grid_border.setVisibility(View.INVISIBLE);
}
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
}