输入和导航
随着 Android 应用出现在 Chrome 操作系统和平板电脑等其他大尺寸设备上,我们看到,用户在 Android 应用中又重新开始使用键盘导航。在 Android O 中,我们又再次使用键盘作为导航输入设备,从而为基于箭头键和 Tab 键的导航构建了一种更可靠并且可预测的模型。
尤其要指出的是,我们对元素焦点行为做出以下变更:
-
现在,如果您没有为 View对象(前景或背景图片)定义任何焦点状态颜色,框架会为 View设置默认的焦点突出显示颜色。此焦点突出显示标志是基于操作组件主题背景的涟漪图片。
-
如果您不希望 View对象在接收焦点时使用此默认突出显示标志,请在包含 View的布局 XML 文件中将 android:defaultFocusHighlightEnabled属性设置为 false ,或者将 false传递至应用界面逻辑中的 setDefaultFocusHighlightEnabled ( )。
-
要测试键盘输入对界面元素焦点有何影响,您可以启用 Drawing > Show layout bounds开发者选项。在 Android O 中,此选项在当前具有焦点的元素上显示一个 “X” 图标。
另外,Android O 中的所有工具栏元素自动组成键盘导航键区,用户可以更加轻松地导航进入和离开每个作为一个整体的工具栏。
如需详细了解如何在您的应用中改善对键盘导航的支持,请阅读以下链接中的支持键盘导航指南。
(https://developer.android.google.cn/training/keyboard-input/navigation.html)
本文前面均引自已有文章,主要重点介绍关于 android:defaultFocusHightEnabled的使用原理:
frameworks/base/core/java/android/view/View.java#20140
> 20209 private void switchDefaultFocusHighlight() { > 20210 if (isFocused()) { > 20211 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, > 20212 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); > 20213 final boolean active = mDefaultFocusHighlight != null; > 20214 if (needed && !active) { // 表示此View有焦点,需要设置selectableItemBackground背景 > 20215 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); > 20216 } else if (!needed && active) { > 20217 // The highlight is no longer needed, so tear it down. > 20218 setDefaultFocusHighlight(null); > 20219 } > 20220 } > 20221 } /// 系统默认的selectableItemBackground背景高亮 > 20140 private Drawable getDefaultFocusHighlightDrawable() { > 20141 if (mDefaultFocusHighlightCache == null) { > 20142 if (mContext != null) { > 20143 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; > 20144 final TypedArray ta = mContext.obtainStyledAttributes(attrs); > 20145 mDefaultFocusHighlightCache = ta.getDrawable(0); > 20146 ta.recycle(); > 20147 } > 20148 } > 20149 return mDefaultFocusHighlightCache; > 20150 }
isDefaultFocusHighlightNeeded()函数的定义:
21280 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 21281 final boolean lackFocusState = (background == null || !background.isStateful() 21282 || !background.hasFocusStateSpecified()) 21283 && (foreground == null || !foreground.isStateful() 21284 || !foreground.hasFocusStateSpecified()); 21285 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 21286 && isAttachedToWindow() && sUseDefaultFocusHighlight; 21287 }
表示是否默认的焦点高亮开启;当非触摸模式,getDefaultFocusHighlightEnabled()的View_defaultFocusHighlightEnabled
xml配置值为true时, 且没有有效的设置背景焦点状态,表示开启;因此,android:defaultFocusHighlightEnabled属性设置为 false即可关闭默认焦点高亮。
在View.java的draw()方法中,调用drawDefaultFocusHighlight()会绘制默认的焦点高亮:
也就是当setDefaultFocusHighlight前面设置过后,mDefaultFocusHighlight才不会为null,才会绘制具体默认背景(selectableItemBackground)
21313 private void drawDefaultFocusHighlight(Canvas canvas) { 21314 if (mDefaultFocusHighlight != null) { 21315 if (mDefaultFocusHighlightSizeChanged) { 21316 mDefaultFocusHighlightSizeChanged = false; 21317 final int l = mScrollX; 21318 final int r = l + mRight - mLeft; 21319 final int t = mScrollY; 21320 final int b = t + mBottom - mTop; 21321 mDefaultFocusHighlight.setBounds(l, t, r, b); 21322 } 21323 mDefaultFocusHighlight.draw(canvas); 21324 } 21325 }
我们也可以在View的XML中自己添加:
android:defaultFocusHighlightEnabled="false" android:background="?android:selectableItemBackground"
实现视图背景,此效果关闭夏天默认的,使用background具有鼠标悬停高亮效果。