2017-07-31 114 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類是你想要的。