记Android8.0输入和导航变更引起的bug

最近测试团队的妹子再测试 android 8.0的适配工作,提过来一个特别诡异的 bug,这里 mark 一下。
bug 如下: 从某个页面分享到 qq 好友之后,再返回此页面,Actionbar部分莫名其妙颜色发生了变化。具体情况如下图

对于这个 bug 最开始考虑是不是分享回来后不小心改了 actionBar 的颜色;于是进行排查,但是结果是悲伤的,没有发现任何关于更改 ActionBar 颜色的代码。
于是向测试小姐姐询问了,具体产生的机型和系统版本。最后发现只有在 android 8.0的系统上出现这个问题。于是拿来8.0系统进行 debug 调试,依然没有发现任何问题。
后来团队小伙伴,查阅了一系列的资料后发现这个应该是由于 Android 8.0输入和导航的变更引起的。
官方文档描述如下:
尤其要指出的是,我们对元素焦点行为做出以下变更:

  • 现在,如果您没有为 View 对象(前景或背景图片)定义任何焦点状态颜色,框架会为 View 设置默认的焦点突出显示颜色。此焦点突出显示标志是基于操作组件主题背景的涟漪图片。
  • 如果您不希望 View 对象在接收焦点时使用此默认突出显示标志,请在包含 View 的布局 XML 文件中将 android:defaultFocusHighlightEnabled 属性设置为 false,或者将 false 传递至应用界面逻辑中的 setDefaultFocusHighlightEnabled()。
    要测试键盘输入对界面元素焦点有何影响,您可以启用 Drawing > Show layout bounds 开发者选项。在 Android 8.0 中,此选项在当前具有焦点的元素上显示一个“X”图标。
    另外,Android 8.0 中的所有工具栏元素自动组成键盘导航键区,用户可以更加轻松地导航进入和离开每个作为一个整体的工具栏。

经过我们测试确实是这个问题导致的。那么查到了原因如何解决比较好呢。我们尝试了两种方案:
方案一: case by case 的查看几个有问题的页面,设置相应焦点变化 View 的setDefaultFocusHighlightEnabled(false);这样是能够解决当前的问题。但是不能保证,当前页面其他 view 不出现这种状况。这种方案的局限性很明显,一要排查有问题的页面;二不能保证其他 view 不出问题。
方案二:
之后我们对源码进行了查看,发现系统寻找一个合适的 view 给它设置焦点颜色。于是我们猜想是不是可以给根布局 add 一个 view 或者获取一个跟布局下的 view,设置它可以获取交单,然后让系统每次设置此 View 作为焦点 view。 我们同时发现网上确实已经有同学使用了这样的方案。
具体实现如下:
在 BaseActivity 的 onPostCreate 之后进行如下设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  @Override
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
setRootViewDefaultFocusHighlight();
}
//添加一个1*1像素的 view
private void setRootViewDefaultFocusHighlight () {
//此方法只能在Android O上使用
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ViewGroup root = ((ViewGroup)findViewById(android.R.id.content));
if (root != null) {
View view = new View(getContext());
view.setFocusable(true);
view.setFocusableInTouchMode(true);
view.requestFocus();
view.requestFocusFromTouch();
view.setDefaultFocusHighlightEnabled(false);
root.addView(view, new ViewGroup.LayoutParams(1, 1));
}
}
}
//或者直接使用 第一个 view
private void setRootViewDefaultFocusHighlight2 () {
//此方法只能在Android O上使用
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
View root = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0);
if (root != null) {
root.setFocusable(true);
root.setFocusableInTouchMode(true);
root.requestFocus();
root.requestFocusFromTouch();
root.setDefaultFocusHighlightEnabled(false);
}
}
}