我正在尝试使用辅助功能服务在屏幕上获取TextView的X和Y位置,以找到TextView,这可能吗?我发现的一切都需要你先触摸屏幕。以下是我如何获取节点信息的方法。
public class MyAccessibilityService extends AccessibilityService {
@TargetApi(16)
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
AccessibilityNodeInfo source = event.getSource();
}
}
发布于 2017-08-01 03:54:44
您可以随时从辅助功能服务中任意搜索可访问性视图层次结构!不过,我建议您在某种类型的可访问性事件的上下文中这样做,因为这样您就可以确保有要遍历的屏幕内容!在随机回调中这样做充其量是很挑剔的。下面是一个合理的可访问性配置XML文件,用于这些目的:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/accessibility_service_description"
android:accessibilityEventTypes="typeWindowContentChanged|typeWindowsChanged|typeWindowStateChanged"
android:accessibilityFlags="flagReportViewIds|flagIncludeNotImportantViews"
android:canRetrieveWindowContent="true"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="1000"
android:settingsActivity=".SettingsActivity"
/>
下面是对其中几个领域的一些评论。
android:notificationTimeout="1000“
每秒钟只检索一次给定类型的可访问性事件!对于列出的事件,任何较低的设置都将非常冗长。我们只是依靠这个来调用我们的回调并确保我们有节点。就这些目的而言,每秒一次就太棒了。必要时调整。
android:accessibilityEventTypes="typeWindowContentChanged|typeWindowsChanged|typeWindowStateChanged“
粗略地说,这是允许您捕获所有屏幕更改事件的事件子集。打开一个新窗户..。扫描视图层次结构!
android:accessibilityFlags="flagReportViewIds|flagIncludeNotImportantViews“
标志包含不重要的视图将在AccessibilityNodeInfo层次结构中包含更多的视图。具体来说,很多布局视图,以及Android操作系统通常认为对可访问性来说是不必要的。我喜欢包括这一点,因为这也是一个开发者可调节的属性,而Android开发人员在可访问性方面也是众所周知的不知道。最好把所有的东西都拿出来,自己整理一下!
好的,这就是你的服务配置!现在,剩下的都很简单。您要做的是通过根节点的子节点进行递归,直到找到一个TextView节点。我已经在下面设置了一个愚蠢的服务,它将在每个屏幕更新中找到第一个TextView节点(除非在上面的服务配置XML下,它们每秒不止一次出现),然后记录它的屏幕坐标。
class MyAccessibilityService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent e) {
//You can actually call getRootInActiveWindow() any time!
//Doing so here ensures that the screen is in a reasonable state
//and not in the middle of rendering or something else silly.
final AccessibilityNodeInfo textNodeInfo = findTextViewNode(getRootInActiveWindow());
if (textNodeInfo == null) return;
Rect rect = new Rect();
textNodeInfo.getBoundsInScreen(rect);
Log.i(A11yService.class.getSimpleName(), "The TextView Node: " + rect.toString());
}
public AccessibilityNodeInfo findTextViewNode(AccessibilityNodeInfo nodeInfo) {
//I highly recommend leaving this line in! You never know when the screen content will
//invalidate a node you're about to work on, or when a parents child will suddenly be gone!
//Not doing this safety check is very dangerous!
if (nodeInfo == null) return null;
Log.v(A11yService.class.getSimpleName(), nodeInfo.toString());
//Notice that we're searching for the TextView's simple name!
//This allows us to find AppCompat versions of TextView as well
//as 3rd party devs well names subclasses... though with perhaps
//a few poorly named unintended stragglers!
if (nodeInfo.getClassName().toString().contains(TextView.class.getSimpleName())) {
return nodeInfo;
}
//Do other work!
for (int i = 0; i < nodeInfo.getChildCount(); i++) {
AccessibilityNodeInfo result = findTextViewNode(nodeInfo.getChild(i));
if (result != null) return result;
}
return null;
}
//Required for a valid Accessibility Service.
@Override
public void onInterrupt() {}
}
您还可以找到我构建的名为无障碍服务实用程序的开放源代码库,它可以使所有这些事情变得更容易!A11yNodeInfoMatcher
类就是您想要的。
https://stackoverflow.com/questions/45423728
复制相似问题