android TV焦点适配

目录

遥控器适配基本方法:

焦点获取状态全局监听:

自定义View以实现获焦样式:

踩坑:

 

遥控器适配基本方法:

1.XML文件中

android:focusable:设置一个控件能否获得焦点

android:background:设置在作为背景的drawable

android:nextFocusDown:定义下一个获得焦点的控件当按下键时

android:nextFocusUp:定义下一个获得焦点的控件当按上键时

android:nextFocusLeft:定义下一个获得焦点的控件当按左键时

android:nextFocusRight:定义下一个获得焦点的控件当按右键时

<requestFocus/>:强制设置一个焦点到指定的view或它的一个子类,前提是android:focusable为true

 

2.activiy中

public boolean dispatchKeyEvent (KeyEvent event)

public boolean onKeyDown (int keyCode, KeyEvent event)

public boolean onKeyUp(int keyCode, KeyEvent event)

public boolean dispatchKeyEventPreIme (KeyEvent event)

public boolean onKeyPreIme (int keyCode, KeyEvent event)

大部分情况下我们重写onKeyDown或者onKeyUp就可以满足监听遥控器按键的事件,但需要在输入法之前做一些动作,便需要重写onKeyPreIme。

 

3.view

public void setOnKeyListener (View.OnKeyListener l)
public boolean dispatchKeyEvent (KeyEvent event) 
public boolean dispatchKeyEventPreIme (KeyEvent event)

 

焦点获取状态全局监听:

Android中提供了ViewTreeObserver来监听View树中一系列状态变化
ViewTreeObserver的解释:
这是一个注册监听视图树的观察者(observer),在视图树种全局事件改变时得到通知。这个全局事件不仅还包括整个树的布局,从绘画过程开始,触摸模式的改变等。ViewTreeObserver不能够被应用程序实例化,因为它是由view提供,通过getViewTreeObserver()可以获取到该实例。

该类中有以下接口
interface  ViewTreeObserver.OnGlobalFocusChangeListener         
当在一个视图树中的焦点状态发生改变时,所要调用的回调函数的接口类
interface  ViewTreeObserver.OnGlobalLayoutListener
当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时,所要调用的回调函数的接口类
interface  ViewTreeObserver.OnPreDrawListener
当一个视图树将要绘制时,所要调用的回调函数的接口类
interface  ViewTreeObserver.OnScrollChangedListener
当一个视图树中的一些组件发生滚动时,所要调用的回调函数的接口类
interface  ViewTreeObserver.OnTouchModeChangeListener
当一个视图树的触摸模式发生改变时,所要调用的回调函数的接口类

这里我们只用ViewTreeObserver.OnGlobalFocusChangeListener,通过调用ViewTreeObserver实例的addOnGlobalFocusChangeListener方法来给view树设置view的focus发生变化的监听。通过这个监听,可以全局设置一个焦点样式View,覆盖在获取焦点的View上,同时可以进行一些焦点样式View、失焦view和获焦view的动画。这个方法的缺陷是不是特别灵活,如果样式比较丰富,需要大量的if else逻辑支持。

 

自定义View以实现获焦样式:

刚才提到ViewTreeObserver.addOnGlobalFocusChangeListener这种方式设置获焦状态不够灵活,而且作为一个懒人,我并不愿意创建大量的selector,shape等文件去实现各种各样的样式,这样自定义view就自然而然的成为了我们的选择。

核心类:ColorStateList,StateListDrawable,以下是是ColorStateList的构造函数

public ColorStateList(int[][] states, @ColorInt int[] colors) {
    mStateSpecs = states;
    mColors = colors;

    onColorsChanged();
}

可见他的内部维护了一个状态数组和一个相应的颜色数组,我们可以在代码里setBackgroundColor(ColorStateList);这样在状态改变时,就会相应的改变颜色,StateListDrawable的使用和ColorStateList基本一致:

int[][] states = new int[5][];
states[0] = new int[]{-android.R.attr.state_enabled};//unable
states[1] = new int[]{android.R.attr.state_focused};//focused
states[2] = new int[]{android.R.attr.state_pressed};//pressed
states[3] = new int[]{android.R.attr.state_checked};//checked
states[4] = new int[]{android.R.attr.state_selected};//selected
states[5] = new int[]{android.R.attr.state_enabled};//normal

int[] colors = new int[]{mTextColorUnable, mTextColorFocused, mTextColorPressed, mTextColorSelected, mTextColorNormal};
mTextColorStateList = new ColorStateList(states, colors);
mView.setTextColor(mTextColorStateList);

踩坑:

1.设置focusableInTouchMode = true后点击事件需要点击到第二次才会响应点击,这是因为View的onTouchEvent里面会先去判断当前view是否能获取焦点并focusableInTouchMode = true,如果成立,则requestFocus()并返回,不再往下执行。当前解决办法是自定义view中重写:

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //解决设置focusableInTouchMode=true后第一次点击事件失效
        if (hasFocusable()){
            requestFocus();
        }
        return super.onTouchEvent(event);
    }

2.focusable = false的时候focusableInTouchMode一定是false;focusableInTouchMode = false的时候focusable不一定是false。

3.获焦后view放大在linnerlayout和recyclerview中可能展示会有问题,解决方法为重写他们的getChildDrawingOrder:

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {
        if (childCount == 0) {
            return super.getChildDrawingOrder(childCount, i);
        }
        int newOrder = i;
        if (getChildAt(i).isFocused()) {
            newOrder = childCount - 1;
        } else {
            if (i == childCount - 1) {
                View focusChild = findFocus();
                int indexOfChild = indexOfChild(focusChild);
                newOrder = (indexOfChild >= 0 ? indexOfChild : i);
            }
        }
        return super.getChildDrawingOrder(childCount, newOrder);
    }

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值