Android自動化學(xué)習(xí)4--uiautomator2判斷是否滑動到頁面底部

前言

我們在使用 uiautomator2 做UI自動化時,有時需要進(jìn)行多次滑動操作伍派,比如我進(jìn)入某個APP頁面定位某個元素诉植,如果該元素不存在晾腔,那么我可能會一直進(jìn)行上滑操作建车,如果定位到該元素就停止繼續(xù)滑動扩借。

  • 一般的情況,如果頁面是固定不變的內(nèi)容缤至,那么我們可以嘗試并計算出大概需要滑動多少次才能到該元素的區(qū)域潮罪,這個時候我們直接把滑動次數(shù)寫死就好。

  • 另一種情況领斥,如果頁面是經(jīng)常變化的內(nèi)容嫉到,這個時候我們就不知道到底需要滑動多少次,也許需要滑動到頁面底部月洛,才能判斷該元素是否存在何恶。

今天我們就學(xué)習(xí)下,如何在 uiautomator2 中判斷是否已滑動到頁面底部。

利用 dump_hierarchy() 獲取界面UI結(jié)構(gòu)

在 uiautomator2 中碎节,我們通過 dump_hierarchy() 方法獲取到當(dāng)前界面的UI結(jié)構(gòu)信息,同時該方法會把數(shù)據(jù)以 XML 形式的字符串進(jìn)行返回。

import uiautomator2 as u2

d = u2.connect()
res = d.dump_hierarchy()

print(res)

返回的形式大致如下纲堵,它反應(yīng)了當(dāng)前頁面的所有UI層次結(jié)構(gòu)關(guān)系茂附。

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<hierarchy rotation="0">
  <node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
    <node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
      <node index="0" text="" resource-id="android:id/content" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
        <node index="0" text="" resource-id="com.sec.android.app.launcher:id/launcher" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
          <node index="0" text="" resource-id="com.sec.android.app.launcher:id/drag_layer" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
            <node index="0" text="" resource-id="com.sec.android.app.launcher:id/apps_view" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
              <node index="0" text="" resource-id="com.sec.android.app.launcher:id/apps_content" class="com.android.launcher3.allapps.view.AppsPagedView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="true" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
                <node index="3" text="" resource-id="" class="android.view.ViewGroup" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[23,225][1057,1833]">
                  <node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[23,237][1057,1833]">
                    <node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="ATX" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="true" password="false" selected="false" visible-to-user="true" bounds="[23,237][274,549]">
                      <node index="0" text="" resource-id="com.sec.android.app.launcher:id/iconview_imageView" class="android.widget.ImageView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[67,256][229,418]" />
                      <node index="2" text="ATX" resource-id="com.sec.android.app.launcher:id/iconview_titleView" class="android.widget.TextView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[114,424][183,478]" />
                    </node>
                  </node>
                </node>
              </node>
              <node index="1" text="" resource-id="com.sec.android.app.launcher:id/apps_searchbar_container" class="android.widget.LinearLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,99][1080,207]">
                <node index="0" text="" resource-id="com.sec.android.app.launcher:id/app_search_wrapper" class="android.widget.RelativeLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[60,99][1020,207]">
                  <node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[60,99][1020,207]">
                    <node index="0" text="" resource-id="com.sec.android.app.launcher:id/app_search_edit_text_wrapper" class="android.widget.LinearLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[60,99][774,207]">
                      <node index="0" text="  搜索手機(jī)" resource-id="com.sec.android.app.launcher:id/app_search_edit_text" class="android.widget.EditText" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="true" password="false" selected="false" visible-to-user="true" bounds="[72,99][774,207]" />
                    </node>
                    <node index="1" text="" resource-id="com.sec.android.app.launcher:id/voice_search_button" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[774,99][894,207]">
                      <node index="0" text="" resource-id="com.sec.android.app.launcher:id/voice_search_icon_imageview" class="android.widget.ImageButton" package="com.sec.android.app.launcher" content-desc="語音搜索" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[774,99][894,207]" />
                    </node>
                    <node index="2" text="" resource-id="com.sec.android.app.launcher:id/apps_search_divider" class="android.view.View" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[915,129][918,177]" />
                    <node index="3" text="" resource-id="com.sec.android.app.launcher:id/more_button_search" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[939,117][1011,189]">
                      <node index="0" text="" resource-id="com.sec.android.app.launcher:id/more_icon_imageview" class="android.widget.ImageButton" package="com.sec.android.app.launcher" content-desc="更多選項(xiàng)" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[939,117][1011,189]" />
                    </node>
                  </node>
                  <node index="1" text="" resource-id="" class="android.widget.LinearLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[60,204][1020,207]" />
                </node>
              </node>
            </node>
            <node index="2" text="" resource-id="com.sec.android.app.launcher:id/apps_page_indicator" class="android.widget.LinearLayout" package="com.sec.android.app.launcher" content-desc="第 4 頁,共 4 頁。" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[424,1821][655,1872]">
              <node NAF="true" index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[424,1821][475,1872]">
                <node index="0" text="" resource-id="com.sec.android.app.launcher:id/inactive" class="android.widget.ImageView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[424,1821][475,1872]" />
              </node>
              <node NAF="true" index="1" text="" resource-id="" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[484,1821][535,1872]">
                <node index="0" text="" resource-id="com.sec.android.app.launcher:id/inactive" class="android.widget.ImageView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[484,1821][535,1872]" />
              </node>
              <node NAF="true" index="2" text="" resource-id="" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[544,1821][595,1872]">
                <node index="0" text="" resource-id="com.sec.android.app.launcher:id/inactive" class="android.widget.ImageView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[544,1821][595,1872]" />
              </node>
              <node NAF="true" index="3" text="" resource-id="" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[604,1821][655,1872]">
                <node index="1" text="" resource-id="com.sec.android.app.launcher:id/active" class="android.widget.ImageView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[604,1821][655,1872]" />
              </node>
            </node>
          </node>
        </node>
      </node>
    </node>
  </node>
</hierarchy>

判斷已經(jīng)滑動到頁面底部

我們可以利用 dump_hierarchy() 獲取界面UI結(jié)構(gòu)婿牍,那么需要怎么判斷當(dāng)前是否已滑動到底了呢慎菲?其實(shí)很簡單,我們只需要判斷每次滑動前的UI結(jié)構(gòu)信息,與滑動后的UI結(jié)構(gòu)信息一致,那么就可以看作是滑動到底部了稻轨。

import uiautomator2 as u2
import time

d = u2.connect()

while True:
    # 獲取每次滑動前頁面下半部分的所有元素
    page_content = d.dump_hierarchy()[(len(d.dump_hierarchy()) // 2):]
    d.swipe_ext("up")
    time.sleep(0.5)
    # 獲取每次滑動后頁面下半部分的所有元素线欲,并與上一次滑動前的頁面元素對比,頁面元素沒有變化時跳出循環(huán)
    new_page_content = d.dump_hierarchy()[(len(d.dump_hierarchy()) // 2):]
    if new_page_content == page_content:
        break

print("swipe end")
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末廓鞠,一起剝皮案震驚了整個濱河市砌们,隨后出現(xiàn)的幾起案子峻堰,更是在濱河造成了極大的恐慌拇砰,老刑警劉巖尸诽,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異辅鲸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人迅涮,你說我怎么就攤上這事群嗤≡烁遥” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵忠售,是天一觀的道長传惠。 經(jīng)常有香客問我,道長稻扬,這世上最難降的妖魔是什么卦方? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮泰佳,結(jié)果婚禮上盼砍,老公的妹妹穿的比我還像新娘。我一直安慰自己逝她,他們只是感情好浇坐,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著黔宛,像睡著了一般近刘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上臀晃,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天觉渴,我揣著相機(jī)與錄音,去河邊找鬼积仗。 笑死疆拘,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的寂曹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼隆圆!你這毒婦竟也來了漱挚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤渺氧,失蹤者是張志新(化名)和其女友劉穎旨涝,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侣背,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡白华,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了贩耐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弧腥。...
    茶點(diǎn)故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖潮太,靈堂內(nèi)的尸體忽然破棺而出管搪,到底是詐尸還是另有隱情,我是刑警寧澤铡买,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布更鲁,位于F島的核電站,受9級特大地震影響奇钞,放射性物質(zhì)發(fā)生泄漏澡为。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一景埃、第九天 我趴在偏房一處隱蔽的房頂上張望缀壤。 院中可真熱鬧,春花似錦纠亚、人聲如沸塘慕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽图呢。三九已至,卻和暖如春骗随,著一層夾襖步出監(jiān)牢的瞬間蛤织,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工鸿染, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留指蚜,地道東北人。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓涨椒,卻偏偏與公主長得像摊鸡,于是被迫代替她去往敵國和親绽媒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容

  • UIAutomator2 的使用 簡介 uiautomator2是一個python庫免猾,用于Android的UI自動...
    Mr_lonely閱讀 1,352評論 0 0
  • Mark一下是辕,每次都得找。最近在做app自動化測試的項(xiàng)目猎提,希望原作者不介意获三。只是Mark一下。后續(xù)有動作锨苏,再更新疙教。...
    博士cium閱讀 2,852評論 0 3
  • 1、判斷l(xiāng)istView滑動到最后一個Item的內(nèi)容的底部(即listview不能再向下滑): 注:view的ge...
    木卯卯閱讀 9,139評論 1 5
  • https://github.com/openatx/uiautomator2 平時用的最多也最順手的一個Andr...
    welder77閱讀 19,875評論 4 7
  • 表情是什么伞租,我認(rèn)為表情就是表現(xiàn)出來的情緒贞谓。表情可以傳達(dá)很多信息。高興了當(dāng)然就笑了肯夏,難過就哭了经宏。兩者是相互影響密不可...
    Persistenc_6aea閱讀 125,071評論 2 7