Android onAccessibilityEvent 获取TextView的X和Y位置

6

我正在尝试使用辅助功能服务查找TextView并获取其在屏幕上的X和Y位置,但是否可能无需先触摸屏幕呢?我的节点信息获取方式如下:

public class MyAccessibilityService extends AccessibilityService {

    @TargetApi(16)
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        AccessibilityNodeInfo source = event.getSource();
    }
}
1个回答

14
你可以随时从无障碍服务中任意搜索可访问性视图层次结构!不过,我建议在某种类型的可访问性事件的上下文中进行搜索,这样可以确保有屏幕内容可遍历!在随机回调中这样做可能会出现问题。以下是一个合理的可访问性配置 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() {}
}

你还可以寻找我构建的开源库Accessibility Service Utilities,它可以让所有这些东西变得更加容易!A11yNodeInfoMatcher类是你想要的。

我能够获取视图的矩形,但它的位置与窗口管理器不方便。我该如何解决?你有什么建议吗? - JDevoloper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接