您可以隨時隨地從輔助服務中搜索輔助功能視圖層次結構!雖然我建議從某種類型的可訪問性事件的上下文中這樣做,但您確保有屏幕內容可以遍歷!這樣做隨機回調是最好的挑剔。這是合理的無障礙配置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類是你想要的。