Android 焦点设计与调试规范

原创
2022/12/02 10:04
阅读数 366

一、问题

我们知道,RecyclerView、ListView作为ItemView可以回收的View组建,时常伴随nofityDatasetChanged方法调用,导致removeView 触发clearFocus,出现焦点丢失的问题。那么我们应该如何解决这类问题呢?此外,我们对于焦点的丢失如何去调试呢 ?

 

二、关于焦点的理解

2.1 焦点的规则

/*
 *
 *【1】从根节点深度优先搜索
 *【2】符合enable,visible,focusable是最基本的条件,否则无法获焦
 *【3】targetSDK >= android P时,0像素View无法聚焦
 *【4】正在layout的布局无法聚焦
 *【5】父view 设置了FOCUS_BLOCK_DESCENDANTS,父View优先获取焦点
 *【6】removeView,requestLayout,非visible,focusable=false,enable=false,notifyDatasetChanged 会或者容易失去焦点
 *【7】获焦后再次requestFocus可能导致焦点丢失,因此使用焦点前最好先判断View.isFocused()
 *【8】没有attachToWindow的无法获取焦点
 *【9】onWindowFocusChanged之前调用Request
*/

2.2 焦点模式和触屏模式

Android中默认支持两种模式,触发KeyEvent会自动切换为Focus模式,触发TouchEvent会自动切换为触屏模式。可以利用View.isInTouchMode()判断

2.3 Window(或Activity)焦点的生命周期

1: entry: onStart---->onResume---->onAttachedToWindow----------->onWindowVisibilityChanged--visibility=0---------->onWindowFocusChanged(true)-

2. exit:  onPause---->onStop---->onWindowFocusChanged(false)  ---------------------- (lockscreen)

3. exit : onPause----->onWindowFocusChanged(false)-------->onWindowVisibilityChanged--visibility=8------------>onStop(to another activity

 

三、焦点恢复

焦点恢复有很多种方法,但是前提保证列表获焦在刷新之后,否则可能仍然出现焦点丢失,简单的方法就是 在生命周期中保存Activity.getCurrentFocus(),Activty获焦之后在恢复回来。

 

四、二次定焦

为什么需要知道二次定焦呢?因为有些很特殊的需求,比如视频自动播放的那种列表,当从其他地方来查找焦点,无疑是可见的第一条或者最后一条,如果想定焦到当前播放的那一条如何做呢?这个时候就需要二次定焦,先把焦点给RecyclerView或者ListView,然后RecyclerView中查找当前播放的那一条,赋予焦点,当然这个肯定得借助OnGlobalFocusChangeListener来实现,当然也要判定焦点转移是不是在View内部,方法如下

public View getDeepestFocusedChild() {
    View v = this;
    while (v != null) {
        if (v.isFocused()) {
            return v;
        }
        v = v instanceof ViewGroup ? ((ViewGroup) v).getFocusedChild() : null;
    }
    return null;
}

 

五、列表焦点设计规范

由于RecyclerView滑动过程容易复用View导致失去焦点,因此,在ItemView移动时,务必要在焦点所在的可见Item在贴着顶部和底部,因此移动过程中,进行自动滑动操作,可以有效避免焦点的丢失,可以参考google-leanback的实现

 

六、焦点的调试

6.1、焦点监听

调试焦点也很容,利用onGlobalFocusChangeListener ,准确把握默焦点的转移。

6.2 用Pad或者手机模拟TV

pad和TV默认是触屏版,因此需要设置foucusableInTouchMode,或者用ADB Chrome也可以自动切换为焦点模式。

当然,触屏版本默认设置focusableInTouchMode是不够的,必须和setOnClickListener或者setClickable(true)一起使用,大多数情况下可以获取焦点的View本身时可以点击的。

 

 

 

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部