下面列出了android.support.v4.view.accessibility.AccessibilityNodeInfoCompat#obtain ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
if (DrawerLayout.CAN_HIDE_DESCENDANTS) {
super.onInitializeAccessibilityNodeInfo(host, info);
} else {
AccessibilityNodeInfoCompat superNode = AccessibilityNodeInfoCompat.obtain(info);
super.onInitializeAccessibilityNodeInfo(host, superNode);
info.setSource(host);
ViewParent parent = ViewCompat.getParentForAccessibility(host);
if (parent instanceof View) {
info.setParent((View) parent);
}
copyNodeInfoNoChildren(info, superNode);
superNode.recycle();
addChildrenForAccessibility(info, (ViewGroup) host);
}
info.setClassName(DrawerLayout.class.getName());
info.setFocusable(false);
info.setFocused(false);
info.removeAction(AccessibilityActionCompat.ACTION_FOCUS);
info.removeAction(AccessibilityActionCompat.ACTION_CLEAR_FOCUS);
}
/**
* Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
* parent view populated with its virtual descendants.
*
* @return An {@link AccessibilityNodeInfoCompat} for the parent view.
*/
private AccessibilityNodeInfoCompat getNodeForRoot() {
// The root node is identical to the parent node, except that it is a
// child of the parent view and is populated with virtual descendants.
final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain(mHost);
ViewCompat.onInitializeAccessibilityNodeInfo(mHost, node);
// Add the virtual descendants.
final LinkedList<Integer> virtualViewIds = new LinkedList<Integer>();
getVisibleVirtualViewIds(virtualViewIds);
for (Integer virtualViewId : virtualViewIds) {
node.addChild(mHost, virtualViewId);
}
// Set up the node as a child of the parent.
node.setParent(mHost);
node.setSource(mHost, ROOT_ID);
return node;
}
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
final AccessibilityNodeInfoCompat superNode = AccessibilityNodeInfoCompat.obtain(info);
super.onInitializeAccessibilityNodeInfo(host, superNode);
info.setSource(host);
final ViewParent parent = ViewCompat.getParentForAccessibility(host);
if (parent instanceof View) {
info.setParent((View) parent);
}
copyNodeInfoNoChildren(info, superNode);
superNode.recycle();
addChildrenForAccessibility(info, (ViewGroup) host);
}
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
final AccessibilityNodeInfoCompat superNode = AccessibilityNodeInfoCompat.obtain(info);
super.onInitializeAccessibilityNodeInfo(host, superNode);
copyNodeInfoNoChildren(info, superNode);
superNode.recycle();
info.setClassName(SlidingUpPaneLayout.class.getName());
info.setSource(host);
final ViewParent parent = ViewCompat.getParentForAccessibility(host);
if (parent instanceof View) {
info.setParent((View) parent);
}
// This is a best-approximation of addChildrenForAccessibility()
// that accounts for filtering.
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (!filter(child) && (child.getVisibility() == View.VISIBLE)) {
// Force importance to "yes" since we can't read the value.
ViewCompat.setImportantForAccessibility(
child, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
info.addChild(child);
}
}
}
/**
* Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
* host view populated with its virtual descendants.
*
* @return An {@link AccessibilityNodeInfoCompat} for the parent node.
*/
private AccessibilityNodeInfoCompat createNodeForHost() {
final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain(mView);
ViewCompat.onInitializeAccessibilityNodeInfo(mView, node);
// Add the virtual descendants.
final LinkedList<Integer> virtualViewIds = new LinkedList<Integer>();
getVisibleVirtualViews(virtualViewIds);
for (Integer childVirtualViewId : virtualViewIds) {
node.addChild(mView, childVirtualViewId);
}
return node;
}
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
final AccessibilityNodeInfoCompat superNode = AccessibilityNodeInfoCompat.obtain(info);
super.onInitializeAccessibilityNodeInfo(host, superNode);
copyNodeInfoNoChildren(info, superNode);
superNode.recycle();
info.setClassName(SlideFrameLayout.class.getName());
info.setSource(host);
final ViewParent parent = ViewCompat.getParentForAccessibility(host);
if (parent instanceof View) {
info.setParent((View) parent);
}
// This is a best-approximation of addChildrenForAccessibility()
// that accounts for filtering.
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (!filter(child) && (child.getVisibility() == View.VISIBLE)) {
// Force importance to "yes" since we can't read the value.
ViewCompat.setImportantForAccessibility(
child, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
info.addChild(child);
}
}
}
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
if (CAN_HIDE_DESCENDANTS) {
super.onInitializeAccessibilityNodeInfo(host, info);
} else {
// Obtain a node for the host, then manually generate the list
// of children to only include non-obscured views.
final AccessibilityNodeInfoCompat superNode =
AccessibilityNodeInfoCompat.obtain(info);
super.onInitializeAccessibilityNodeInfo(host, superNode);
info.setSource(host);
final ViewParent parent = ViewCompat.getParentForAccessibility(host);
if (parent instanceof View) {
info.setParent((View) parent);
}
copyNodeInfoNoChildren(info, superNode);
superNode.recycle();
addChildrenForAccessibility(info, (ViewGroup) host);
}
info.setClassName(DebugDrawerLayout.class.getName());
// This view reports itself as focusable so that it can intercept
// the back button, but we should prevent this view from reporting
// itself as focusable to accessibility services.
info.setFocusable(false);
info.setFocused(false);
}
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
final AccessibilityNodeInfoCompat superNode = AccessibilityNodeInfoCompat.obtain(info);
super.onInitializeAccessibilityNodeInfo(host, superNode);
copyNodeInfoNoChildren(info, superNode);
superNode.recycle();
info.setClassName(SlidingLayout.class.getName());
info.setSource(host);
final ViewParent parent = ViewCompat.getParentForAccessibility(host);
if (parent instanceof View) {
info.setParent((View) parent);
}
// This is a best-approximation of addChildrenForAccessibility()
// that accounts for filtering.
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (!filter(child) && (child.getVisibility() == View.VISIBLE)) {
// Force importance to "yes" since we can't read the value.
ViewCompat.setImportantForAccessibility(
child, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
info.addChild(child);
}
}
}
/**
* Returns the {@code node} if it matches the {@code filter}, or the first
* matching ancestor. Returns {@code null} if no nodes match.
*/
public static AccessibilityNodeInfoCompat getSelfOrMatchingAncestor(
Context context, AccessibilityNodeInfoCompat node, NodeFilter filter) {
if (node == null) {
return null;
}
if (filter.accept(context, node)) {
return AccessibilityNodeInfoCompat.obtain(node);
}
return getMatchingAncestor(context, node, filter);
}
/**
* Returns the result of applying a filter using breadth-first traversal.
*
* @param context The parent context.
* @param node The root node to traverse from.
* @param filter The filter to satisfy.
* @return The first node reached via BFS traversal that satisfies the
* filter.
*/
public static AccessibilityNodeInfoCompat searchFromBfs(
Context context, AccessibilityNodeInfoCompat node, NodeFilter filter) {
if (node == null) {
return null;
}
final LinkedList<AccessibilityNodeInfoCompat> queue =
new LinkedList<AccessibilityNodeInfoCompat>();
queue.add(AccessibilityNodeInfoCompat.obtain(node));
while (!queue.isEmpty()) {
final AccessibilityNodeInfoCompat item = queue.removeFirst();
if (filter.accept(context, item)) {
return AccessibilityNodeInfoCompat.obtain(item);
}
final int childCount = item.getChildCount();
for (int i = 0; i < childCount; i++) {
final AccessibilityNodeInfoCompat child = item.getChild(i);
if (child != null) {
queue.addLast(child);
}
}
}
return null;
}
private AccessibilityNodeInfoCompat b()
{
AccessibilityNodeInfoCompat accessibilitynodeinfocompat = AccessibilityNodeInfoCompat.obtain(h);
ViewCompat.onInitializeAccessibilityNodeInfo(h, accessibilitynodeinfocompat);
LinkedList linkedlist = new LinkedList();
getVisibleVirtualViews(linkedlist);
Integer integer;
for (Iterator iterator = linkedlist.iterator(); iterator.hasNext(); accessibilitynodeinfocompat.addChild(h, integer.intValue()))
{
integer = (Integer)iterator.next();
}
return accessibilitynodeinfocompat;
}
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
if (CAN_HIDE_DESCENDANTS) {
super.onInitializeAccessibilityNodeInfo(host, info);
} else {
// Obtain a node for the host, then manually generate the list
// of children to only include non-obscured views.
final AccessibilityNodeInfoCompat superNode =
AccessibilityNodeInfoCompat.obtain(info);
super.onInitializeAccessibilityNodeInfo(host, superNode);
info.setSource(host);
final ViewParent parent = ViewCompat.getParentForAccessibility(host);
if (parent instanceof View) {
info.setParent((View) parent);
}
copyNodeInfoNoChildren(info, superNode);
superNode.recycle();
addChildrenForAccessibility(info, (ViewGroup) host);
}
info.setClassName(DrawerLayout.class.getName());
// This view reports itself as focusable so that it can intercept
// the back button, but we should prevent this view from reporting
// itself as focusable to accessibility services.
info.setFocusable(false);
info.setFocused(false);
info.removeAction(AccessibilityActionCompat.ACTION_FOCUS);
info.removeAction(AccessibilityActionCompat.ACTION_CLEAR_FOCUS);
}
/**
* Determines if the supplied {@link View} and {@link AccessibilityNodeInfoCompat} has any
* children which are not independently accessibility focusable and also have a spoken
* description.
* <p>
* NOTE: Accessibility services will include these children's descriptions in the closest
* focusable ancestor.
*
* @param view The {@link View} to evaluate
* @param node The {@link AccessibilityNodeInfoCompat} to evaluate
* @return {@code true} if it has any non-actionable speaking descendants within its subtree
*/
public static boolean hasNonActionableSpeakingDescendants(
@Nullable AccessibilityNodeInfoCompat node,
@Nullable View view) {
if (node == null || view == null || !(view instanceof ViewGroup)) {
return false;
}
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0, count = viewGroup.getChildCount(); i < count; i++) {
View childView = viewGroup.getChildAt(i);
if (childView == null) {
continue;
}
AccessibilityNodeInfoCompat childNode = AccessibilityNodeInfoCompat.obtain();
try {
ViewCompat.onInitializeAccessibilityNodeInfo(childView, childNode);
if (isAccessibilityFocusable(childNode, childView)) {
continue;
}
if (isSpeakingNode(childNode, childView)) {
return true;
}
} finally {
childNode.recycle();
}
}
return false;
}
/**
* Determines if any of the provided {@link View}'s and {@link AccessibilityNodeInfoCompat}'s
* ancestors can receive accessibility focus
*
* @param view The {@link View} to evaluate
* @param node The {@link AccessibilityNodeInfoCompat} to evaluate
* @return {@code true} if an ancestor of may receive accessibility focus
*/
public static boolean hasFocusableAncestor(
@Nullable AccessibilityNodeInfoCompat node,
@Nullable View view) {
if (node == null || view == null) {
return false;
}
ViewParent parentView = ViewCompat.getParentForAccessibility(view);
if (!(parentView instanceof View)) {
return false;
}
AccessibilityNodeInfoCompat parentNode = AccessibilityNodeInfoCompat.obtain();
try {
ViewCompat.onInitializeAccessibilityNodeInfo((View) parentView, parentNode);
if (parentNode == null) {
return false;
}
if (isAccessibilityFocusable(parentNode, (View) parentView)) {
return true;
}
if (hasFocusableAncestor(parentNode, (View) parentView)) {
return true;
}
} finally {
parentNode.recycle();
}
return false;
}
/**
* Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
* host view populated with its virtual descendants.
*
* @return An {@link AccessibilityNodeInfoCompat} for the parent node.
*/
private AccessibilityNodeInfoCompat createNodeForHost() {
final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain(mView);
ViewCompat.onInitializeAccessibilityNodeInfo(mView, node);
// Add the virtual descendants.
final LinkedList<Integer> virtualViewIds = new LinkedList<Integer>();
getVisibleVirtualViews(virtualViewIds);
for (Integer childVirtualViewId : virtualViewIds) {
node.addChild(mView, childVirtualViewId);
}
return node;
}
private AccessibilityNodeInfoCompat createNodeForChild(int virtualViewId) {
AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain();
node.setEnabled(true);
node.setClassName(DEFAULT_CLASS_NAME);
onPopulateNodeForVirtualView(virtualViewId, node);
if (node.getText() == null && node.getContentDescription() == null) {
throw new RuntimeException("Callbacks must add text or a content description in populateNodeForVirtualViewId()");
}
node.getBoundsInParent(this.mTempParentRect);
if (this.mTempParentRect.isEmpty()) {
throw new RuntimeException("Callbacks must set parent bounds in populateNodeForVirtualViewId()");
}
int actions = node.getActions();
if ((actions & 64) != 0) {
throw new RuntimeException("Callbacks must not add ACTION_ACCESSIBILITY_FOCUS in populateNodeForVirtualViewId()");
} else if ((actions & 128) != 0) {
throw new RuntimeException("Callbacks must not add ACTION_CLEAR_ACCESSIBILITY_FOCUS in populateNodeForVirtualViewId()");
} else {
node.setPackageName(this.mView.getContext().getPackageName());
node.setSource(this.mView, virtualViewId);
node.setParent(this.mView);
if (this.mFocusedVirtualViewId == virtualViewId) {
node.setAccessibilityFocused(true);
node.addAction(128);
} else {
node.setAccessibilityFocused(false);
node.addAction(64);
}
if (intersectVisibleToUser(this.mTempParentRect)) {
node.setVisibleToUser(true);
node.setBoundsInParent(this.mTempParentRect);
}
this.mView.getLocationOnScreen(this.mTempGlobalRect);
int offsetX = this.mTempGlobalRect[0];
int offsetY = this.mTempGlobalRect[1];
this.mTempScreenRect.set(this.mTempParentRect);
this.mTempScreenRect.offset(offsetX, offsetY);
node.setBoundsInScreen(this.mTempScreenRect);
return node;
}
}
@Nullable
public static CharSequence getDescription(View view) {
AccessibilityNodeInfoCompat node = createNodeInfoFromView(view);
try {
CharSequence contentDescription = node.getContentDescription();
CharSequence nodeText = node.getText();
boolean hasNodeText = !TextUtils.isEmpty(nodeText);
boolean isEditText = view instanceof EditText;
// EditText's prioritize their own text content over a contentDescription
if (!TextUtils.isEmpty(contentDescription) && (!isEditText || !hasNodeText)) {
return contentDescription;
}
if (hasNodeText) {
return nodeText;
}
// If there are child views and no contentDescription the text of all non-focusable children,
// comma separated, becomes the description.
if (view instanceof ViewGroup) {
final StringBuilder concatChildDescription = new StringBuilder();
final String separator = ", ";
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0, count = viewGroup.getChildCount(); i < count; i++) {
final View child = viewGroup.getChildAt(i);
AccessibilityNodeInfoCompat childNodeInfo = AccessibilityNodeInfoCompat.obtain();
ViewCompat.onInitializeAccessibilityNodeInfo(child, childNodeInfo);
CharSequence childNodeDescription = null;
if (AccessibilityUtil.isSpeakingNode(childNodeInfo, child) &&
!AccessibilityUtil.isAccessibilityFocusable(childNodeInfo, child)) {
childNodeDescription = getDescription(child);
}
if (!TextUtils.isEmpty(childNodeDescription)) {
if (concatChildDescription.length() > 0) {
concatChildDescription.append(separator);
}
concatChildDescription.append(childNodeDescription);
}
childNodeInfo.recycle();
}
return concatChildDescription.length() > 0 ? concatChildDescription.toString() : null;
}
return null;
} finally {
node.recycle();
}
}
/**
* Creates a new instance of this class containing a new copy of
* {@code node}.
*/
public static AccessibilityNodeInfoRef obtain(
AccessibilityNodeInfoCompat node) {
return new AccessibilityNodeInfoRef(
AccessibilityNodeInfoCompat.obtain(node), true);
}
public Content setFirstNode(AccessibilityNodeInfoCompat node) {
AccessibilityNodeInfoUtils.recycleNodes(firstNode);
firstNode = AccessibilityNodeInfoCompat.obtain(node);
return this;
}
/**
* Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
* specified item. Automatically manages accessibility focus actions.
* <p>
* Allows the implementing class to specify most node properties, but
* overrides the following:
* <ul>
* <li>{@link AccessibilityNodeInfoCompat#setPackageName}
* <li>{@link AccessibilityNodeInfoCompat#setClassName}
* <li>{@link AccessibilityNodeInfoCompat#setParent(View)}
* <li>{@link AccessibilityNodeInfoCompat#setSource(View, int)}
* <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
* <li>{@link AccessibilityNodeInfoCompat#setBoundsInScreen(Rect)}
* </ul>
* <p>
* Uses the bounds of the parent view and the parent-relative bounding
* rectangle specified by
* {@link AccessibilityNodeInfoCompat#getBoundsInParent} to automatically
* update the following properties:
* <ul>
* <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
* <li>{@link AccessibilityNodeInfoCompat#setBoundsInParent}
* </ul>
*
* @param virtualViewId The virtual view id for item for which to construct
* a node.
* @return An {@link AccessibilityNodeInfoCompat} for the specified item.
*/
private AccessibilityNodeInfoCompat createNodeForChild(int virtualViewId) {
final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain();
// Ensure the client has good defaults.
node.setEnabled(true);
node.setClassName(DEFAULT_CLASS_NAME);
// Allow the client to populate the node.
onPopulateNodeForVirtualView(virtualViewId, node);
// Make sure the developer is following the rules.
if ((node.getText() == null) && (node.getContentDescription() == null)) {
throw new RuntimeException("Callbacks must add text or a content description in "
+ "populateNodeForVirtualViewId()");
}
node.getBoundsInParent(mTempParentRect);
if (mTempParentRect.isEmpty()) {
throw new RuntimeException("Callbacks must set parent bounds in "
+ "populateNodeForVirtualViewId()");
}
final int actions = node.getActions();
if ((actions & AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS) != 0) {
throw new RuntimeException("Callbacks must not add ACTION_ACCESSIBILITY_FOCUS in "
+ "populateNodeForVirtualViewId()");
}
if ((actions & AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS) != 0) {
throw new RuntimeException("Callbacks must not add ACTION_CLEAR_ACCESSIBILITY_FOCUS in "
+ "populateNodeForVirtualViewId()");
}
// Don't allow the client to override these properties.
node.setPackageName(mView.getContext().getPackageName());
node.setSource(mView, virtualViewId);
node.setParent(mView);
// Manage internal accessibility focus state.
if (mFocusedVirtualViewId == virtualViewId) {
node.setAccessibilityFocused(true);
node.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
} else {
node.setAccessibilityFocused(false);
node.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
}
// Set the visibility based on the parent bound.
if (intersectVisibleToUser(mTempParentRect)) {
node.setVisibleToUser(true);
node.setBoundsInParent(mTempParentRect);
}
// Calculate screen-relative bound.
mView.getLocationOnScreen(mTempGlobalRect);
final int offsetX = mTempGlobalRect[0];
final int offsetY = mTempGlobalRect[1];
mTempScreenRect.set(mTempParentRect);
mTempScreenRect.offset(offsetX, offsetY);
node.setBoundsInScreen(mTempScreenRect);
return node;
}