Android TV焦点处理

之前一直在手机端做开发,换了份工作,要接触车机端,车机和手机端最大的区别就是焦点态的处理,参考了很多开源项目对于焦点态的处理,但都不太符合我的需求。

1.解决的需求

我们的app界面划分几个区域,由6个按键控制,其中300、301主要是在区域里面移动焦点,上下左右是在区域与区域之间切换焦点,之前我们的解决方案是把每个焦点手动加到指定区域,可以实现我们大部分需求,但是过于繁琐,代码量也比较多,设计一套自动扫描布局文件里面的控件到指定区域里面,并且重写ListView、GridView等特殊控件来满足item里面焦点态切换符合需求。

2.方法

首先需要了解的几个知识点:

a.按键事件分发传递的几个方法

activity onkeydown()->view diapatchEvent()->子view dispatchEvent()

b.父控件设置的一个属性对焦点移动影响

android:descendantFocusability

beforeDescendants:父容器会比其子控件率先获得焦点。

afterDescendants:如果没有任何子控件要获得焦点的话,那么父容器才会获得焦点。

blocksDescendants:父容器会阻止其子控件获得焦点(也就是说焦点会由父容器获得)。

c.遍历布局文件下面控件的顺序

这个遍历先后顺序主要是在xml里面编写控件代码先后决定的,这个主要影响后面查找获取焦点控件的顺序。

d.ListView、GridView的特殊处理

针对普通控件焦点态的处理逻辑在activity的onkeyDown方法里面就可以,像ListView、GridView之类设计到item上下切换并且item里面可能还有子控件的焦点态,所以需要在重写这些view的ondispatchEvent方法。

针对第一点自动化扫描将相应的控件添加到指定的焦点区域,定义一个自定义的view继承RelativeLayout、LinearLayout等普通布局代替系统原生的布局,这样我们就可以遍历将不同的控件划分到指定区域。

对于设置父控件android:descendantFocusability主要是用于ListView、GridView等控件item里面焦点的切换使用。

3.目前存在的问题和优化的地方

1.划分焦点区域的焦点态自定义布局不能嵌套

2.对于ListView、GridView等焦点态需要重写点击事件,不能用本身的onItemClick事件

4.部分关键代码

/**
 * 初始化焦点态数据
 *
 * @param mContentView
 */
public void initFocusData(View mContentView) {
    if (!isOpenFocus) {
        return;
    }
    this.curItemPosition = 0;
    this.lastFocusedView = null;

    if (focusBeanList != null && focusBeanList.size() > 0) {
        focusBeanList.clear();
    }

    if (focusViewList != null && focusViewList.size() > 0) {
        focusViewList.clear();
    }
    getFocusViews((ViewGroup) mContentView);
    // 根据Tag来区分焦点态大区并排序
    Collections.sort(focusViewList, new Comparator<View>() {
        @Override
        public int compare(View lhs, View rhs) {
            if (lhs.getTag() != null && rhs.getTag() != null) {
                return (lhs.getTag().toString()).compareTo(rhs.getTag().toString());
            } else {
                return 0;
            }
        }
    });
    for (int i = 0; i < focusViewList.size(); i++) {
        getFocusData(focusViewList.get(i), ((FocusValueCallback) focusViewList.get(i)).getFocusData());
    }
}

/**
 * 添加可以获取焦点view到集合中
 *
 * @param viewGroup
 */
private void getFocusViews(ViewGroup viewGroup) {
    if (viewGroup == null) {
        return;
    }
    if (viewGroup instanceof FocusValueCallback) {
        focusViewList.add(viewGroup);
        return;
    }
    int count = viewGroup.getChildCount();
    for (int i = 0; i < count; i++) {
        View view = viewGroup.getChildAt(i);
        if (view instanceof FocusValueCallback) {
            focusViewList.add(view);
        } else if (view instanceof ViewGroup) {
            getFocusViews((ViewGroup) view);
        }
    }
}
 
/**
 * 获取上个有效的焦点view(循环查找)
 *
 * @param index
 * @return
 */
private View getBeforeFocusView(int index) {
    for (int i = index; i < focusBeanList.size(); i--) {
        View view = focusBeanList.get((i - 1 + focusBeanList.size()) % focusBeanList.size()).getView();
        if (view.isShown() && view.isFocusable()) {
            return view;
        }
    }
    return null;
}
/**
 * 获取下个有效的焦点view(循环查找)
 *
 * @param index
 * @return
 */

private View getNextFocusView(int index) {
    for (int i = index; i < focusBeanList.size(); i++) {
        View view = focusBeanList.get((i + 1) % focusBeanList.size()).getView();
        if (view.isShown() && view.isFocusable()) {
            return view;
        }
    }
    return null;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值