以下基於
python3.8;airtestIDE1.2.13;airtest1.2.4;pocoui1.0.85
注意:Poco框架和Airtest框架很多API是同名的,但使用方法完全不一樣!!!一定不要搞混了,我初學時也經常搞混,這點一定要注意!
具體Poco框架和Airtest框架是什麼關係,可以看之前文章:Airtest Project——UI自動化利器介紹
今天來講Poco的縮放pinch(),大家不要和Airtest框架的pinch()弄混了,參數是不太一樣的。
Airtest的pinch()詳情可以看之前的文章:Airtest API精講之放大縮小pinch()
Poco的pinch分兩種,一種是基於全局操作的pinch、一種是基於UI對象的pinch,兩種API彙總可以看之前的文章
Poco實例(全局操作) API彙總
Poco UI對象 API彙總
Poco基於UI對象的pinch
pinch(direction='in', percent=0.6, duration=2.0, dead_zone=0.1)
縮放
參數:
direction - "in"縮 or "out"放,默認"in"
percent - 縮放距離,該距離是相對於此元素的比例,默認0.6
duration - 縮放時長,默認2秒
dead_zone - 縮放內圈半徑,不能大於percent,默認0.1
異常:
PocoNoSuchNodeException:元素不存在
源碼解析:
# 源碼位置:your_python_path\site-packages\poco\proxy.py
def pinch(self, direction='in', percent=0.6, duration=2.0, dead_zone=0.1):
if direction not in ('in', 'out'):
raise ValueError('Argument `direction` should be one of "in" or "out". Got {}'.format(repr(direction)))
if dead_zone >= percent:
raise ValueError('Argument `dead_zone` should not be greater than `percent`. dead_zoon={}, percent={}'
.format(repr(dead_zone), repr(percent)))
w, h = self.get_size()
x, y = self.get_position()
# focus = self._focus or [0.5, 0.5]
tracks = make_pinching(direction, [x, y], [w, h], percent, dead_zone, duration)
speed = math.sqrt(w * h) * (percent - dead_zone) / 2 / duration
# 速度慢的時候,精度適當要提高,這樣有助於控制準確
ret = self.poco.apply_motion_tracks(tracks, accuracy=speed * 0.03)
return ret
1、第1個if,判斷縮放方向,必須是 "in"縮 or "out"放
2、第1個if,判斷dead_zone不能大於縮放距離。這裏的dead_zone是什麼意思呢,就是下圖中內圓的直徑;而percent縮放距離即是大圓的直徑。
3、中間的代碼塊分別求得UI對象的大小及其中心點在屏幕上的位置,然後代入make_pinching()算出要滑動的軌跡,以及計算出滑動速度。
我們看下make_pinching()的實現:
# 源碼位置:your_python_path\site-packages\poco\utils\multitouch_gesture.py
def make_pinching(direction, center, size, percent, dead_zone, duration):
w, h = size
half_distance = percent / 2
dead_zone_distance = dead_zone / 2
pa0 = center
pb0 = list(pa0)
pa1 = list(pa0)
pb1 = list(pa0)
if direction == 'in':
pa0[0] += w * half_distance
pa0[1] += h * half_distance
pb0[0] -= w * half_distance
pb0[1] -= h * half_distance
pa1[0] += w * dead_zone_distance
pa1[1] += h * dead_zone_distance
pb1[0] -= w * dead_zone_distance
pb1[1] -= h * dead_zone_distance
else:
pa1[0] += w * half_distance
pa1[1] += h * half_distance
pb1[0] -= w * half_distance
pb1[1] -= h * half_distance
pa0[0] += w * dead_zone_distance
pa0[1] += h * dead_zone_distance
pb0[0] -= w * dead_zone_distance
pb0[1] -= h * dead_zone_distance
speed = math.sqrt(w * h) * (percent - dead_zone) / 2 / duration
track_a = MotionTrack([pa0, pa1], speed)
track_b = MotionTrack([pb0, pb1], speed)
return track_a, track_b
大家可以結合上面的圖看,具體計算過程就不推導了,有興趣的話,可以實際代入一個元素的真實的數據計算一下。總之就是計算出2個手指在屏幕上的起點和終點,以生成滑動軌跡。
放大時pa1,pb1就是起點,pa0,pb0就是終點;縮小時pa0,pb0就是起點,pa1,pb1就是終點。
4、最後就是按軌跡執行滑動,看下apply_motion_tracks()源碼:
# 源碼位置:your_python_path\site-packages\poco\pocofw.py
def apply_motion_tracks(self, tracks, accuracy=0.004):
"""
Similar to click but press the screen for the given time interval and then release
Args:
tracks (:py:obj:`list`): list of :py:class:`poco.utils.track.MotionTrack` object
accuracy (:py:obj:`float`): motion accuracy for each motion steps in normalized coordinate metrics.
"""
if not tracks:
raise ValueError('Please provide at least one track. Got {}'.format(repr(tracks)))
tb = MotionTrackBatch(tracks)
return self.agent.input.applyMotionEvents(tb.discretize(accuracy))
這裏最終還是調用的agent的input中的applyMotionEvents(),以UnityPoco爲例,最終調用的也還是Airtest中的方法
# 源碼位置:your_python_path\site-packages\poco\utils\airtest\input.py
def applyMotionEvents(self, events):
if device_platform() != 'Android':
raise NotImplementedError
# Android minitouch/maxtouch only, currently
from airtest.core.android.touch_methods.base_touch import DownEvent, MoveEvent, UpEvent, SleepEvent
mes = []
for e in events:
t = e[0]
if t == 'd':
contact = e[2]
x, y = e[1]
pos = self.get_target_pos(x, y)
me = DownEvent(pos, contact)
elif t == 'm':
contact = e[2]
x, y = e[1]
pos = self.get_target_pos(x, y)
me = MoveEvent(pos, contact)
elif t == 'u':
contact = e[1]
me = UpEvent(contact)
elif t == 's':
how_long = e[1]
me = SleepEvent(how_long)
else:
raise ValueError('Unknown event type {}'.format(repr(t)))
mes.append(me)
current_device().touch_proxy.perform(mes, interval=0)
可以看到最後一行,最終執行的其實還是Airtest框架的perform()方法。可以回過頭再去看看Airtest框架pinch的源碼,最終調用的也是這個perform()方法。
示例:
我們實際使用的時候不需要那麼多複雜的參數,用默認的就夠了。
from airtest.core.api import *
from poco.drivers.unity3d import UnityPoco
auto_setup(__file__)
poco = UnityPoco()
poco('picture').pinch() # 圖片向裏縮小
poco('picture').pinch("out") # 圖片向外放大
Poco基於全局操作的pinch
pinch(direction='in', percent=0.6, duration=2.0, dead_zone=0.1)
縮放
參數:
direction - "in"縮 or "out"放,默認"in"
percent - 縮放距離,該距離是相對於此元素的比例,默認0.6
duration - 縮放時長,默認2秒
dead_zone - 縮放內圈半徑,不能大於percent,默認0.1
源碼解析:
# 源碼位置:your_python_path\site-packages\poco\pocofw.py
def pinch(self, direction='in', percent=0.6, duration=2.0, dead_zone=0.1):
if direction not in ('in', 'out'):
raise ValueError('Argument `direction` should be one of "in" or "out". Got {}'.format(repr(direction)))
if dead_zone >= percent:
raise ValueError('Argument `dead_zone` should not be greater than `percent`. dead_zoon={}, percent={}'
.format(repr(dead_zone), repr(percent)))
tracks = make_pinching(direction, [0.5, 0.5], [1, 1], percent, dead_zone, duration)
speed = (percent - dead_zone) / 2 / duration
# 速度慢的時候,精度適當要提高,這樣有助於控制準確
ret = self.apply_motion_tracks(tracks, accuracy=speed * 0.03)
return ret
全局操作的pinch入參與UI對象的pinch入參是一樣的,而且源碼也幾乎一樣,唯一不一樣的就是全局操作的pinch源碼中,調用make_pinching()時傳入的第2、3個參數是整個屏幕的中心點和大小。
再次強調一下,全局操作是基於整個屏幕的,UI對象是基於元素的。
示例:
from airtest.core.api import *
from poco.drivers.unity3d import UnityPoco
auto_setup(__file__)
poco = UnityPoco()
poco.pinch() # 向裏縮小
poco.pinch("out") # 向外放大
---------------------------------------------------------------------------------
關注微信公衆號即可在手機上查閱,並可接收更多測試分享~