Poco API精講之縮放pinch()
以下基於
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") # 向外放大
---------------------------------------------------------------------------------
關注微信公眾號即可在手機上查閱,並可接收更多測試分享~