2017-07-31 296 views
1

我想要在我的屏幕上使用Accessibility服务来查找TextView的TextView的X和Y位置,这可能吗?我发现的一切都需要你先触摸屏幕。以下是我如何获取我的节点信息。Android onAccessibilityEvent获取TextView的X和Y位置

public class MyAccessibilityService extends AccessibilityService { 

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

回答

3

您可以随时随地从辅助服务中搜索辅助功能视图层次结构!虽然我建议从某种类型的可访问性事件的上下文中这样做,但您确保有屏幕内容可以遍历!这样做随机回调是最好的挑剔。这是合理的无障碍配置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" 
    /> 

下面是关于几个字段专门的一些意见。

机器人:notificationTimeout = “1000”

只有每秒获取给定类型的可访问性事件一次!在列出的事件中,任何较低的设置都是非常详细的。我们只依靠这个来调用我们的回调函数,并确保我们有节点。为了达到这些目的,每秒一次就是DUSTY。根据需要调整。

机器人:accessibilityEventTypes = “typeWindowContentChanged | typeWindowsChanged | typeWindowStateChanged”

粗略地说,这是事件,让你赶上所有的屏幕改变事件的子集。打开一个新窗口...扫描视图层次结构!

机器人:accessibilityFlags = “flagReportViewIds | flagIncludeNotImportantViews”

标志包括并不重要意见将包括AccessibilityNodeInfo层次结构有更多的意见。特别是许多布局视图,Android OS通常不会认为这是必需的。我喜欢离开这个检查,因为这也是一个开发人员可调整的属性,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类是你想要的。