简介
这篇介绍一下 duplicateParentState和descendantFocusability 这两个属性在TV开发中的使用
duplicateParentState
先看下官方说明:
Enables or disables the duplication of the parent's state into this view. When
duplication is enabled, this view gets its drawable state from its parent rather
than from its own internal properties.
- 含义:子View的drawable状态的改变跟随父View的状态的改变,一般和selector使用
- 取值:布尔值
- 对应方法:setDuplicateParentStateEnabled
- 应用场景:
比如TV开发中我们希望ViewGroup获取焦点,里面的子View不获取焦点,但是子View的背景色可以随着ViewGroup聚焦和失焦两种状态变化。看看示例:
xml布局:
FrameLayout focusable获取焦点,然后我们给ImageView设置了一个selector
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#FF0000"
android:focusable="true"
android:orientation="vertical">
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center"
android:background="@drawable/state_change_select" />//应用selector作为背景
</FrameLayout>
selector文件:
聚焦状态时背景色为colorAccent 失焦时背景色是 colorPrimary。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/colorAccent" android:state_focused="true" />
<item android:drawable="@color/colorPrimary" android:state_focused="false" />
</selector>
这样当FrameLayout获取/失去焦点的时候,这两种状态会共享给子View,从而使selector生效。
- 注意:
此属性要生效的话,一种是直接写在xml中;一种是代码中设置,但代码中设置必须在View被添加到ViewGroup之前否则可能不生效。
建议写在xml中。
descendantFocusability
Viewgroup中有此属性。
先看下官方说明:
Set the descendant focusability of this view group. This defines the relationship
between this view group and its descendants when looking for a view to
take focus in {@link #requestFocus(int, android.graphics.Rect)}.
- 含义:这个属性设置后在调用ViewGroup的requestFocus方法时才会有效。ViewGroup调用requestFocus,会根据此属性的值决定焦点是先给子View处理还是自己处理
- 取值:
FOCUS_BEFORE_DESCENDANTS: 父View尝试先处理焦点
FOCUS_AFTER_DESCENDANTS:子View先处理焦点,如果子View不处理父View尝试处理焦点
FOCUS_BLOCK_DESCENDANTS:焦点不往子View进行传递
ViewGroup类的默认值是 FOCUS_BEFORE_DESCENDANTS
- 对应方法:setDescendantFocusability()
我们看下ViewGroup的requestFocus的源码:
//ViewGroup重写了View的 requestFocus(int direction, Rect previouslyFocusedRect)方法。
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
if (DBG) {
System.out.println(this + " ViewGroup.requestFocus direction="
+ direction);
}
int descendantFocusability = getDescendantFocusability();
boolean result;
switch (descendantFocusability) {
case FOCUS_BLOCK_DESCENDANTS: //ViewGroup自己尝试处理焦点
result = super.requestFocus(direction, previouslyFocusedRect);
break;
case FOCUS_BEFORE_DESCENDANTS: { //ViewGroup先自己尝试处理焦点,如果处理不了在往子View去传递
final boolean took = super.requestFocus(direction, previouslyFocusedRect);
result = took ? took : onRequestFocusInDescendants(direction,
previouslyFocusedRect);
break;
}
case FOCUS_AFTER_DESCENDANTS: { //先把焦点给子View去处理,子View处理不了自己在尝试处理
final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
result = took ? took : super.requestFocus(direction, previouslyFocusedRect);
break;
}
default:
throw new IllegalStateException("descendant focusability must be "
+ "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
+ "but is " + descendantFocusability);
}
if (result && !isLayoutValid() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) {
mPrivateFlags |= PFLAG_WANTS_FOCUS;
}
return result;
}
- 应用场景:
有点时候我们只想ViewGroup获取焦点,不想焦点给子View,我们用这个属性的FOCUS_BLOCK_DESCENDANTS值,不让焦点往子View去传递