上期回顧:Poco API精講之縮放pinch()
以下基於
python3.8;airtestIDE1.2.13;airtest1.2.4;pocoui1.0.85
注意:Poco框架和Airtest框架很多API是同名的,但使用方法完全不一樣!!!一定不要搞混了,我初學時也經常搞混,這點一定要注意!
具體Poco框架和Airtest框架是什麼關係,可以看之前文章:Airtest Project——UI自動化利器介紹
今天來講Poco的自定義手勢start_gesture(),大家不要和Airtest框架的Android自定義手勢弄混了。
Airtest的Android自定義手勢詳情可以看之前的文章:Airtest API精講之Android自定義手勢
Poco的start_gesture()分兩種,一種是基於UI對象的start_gesture()、一種是基於全局操作的start_gesture(),兩種API彙總可以看之前的文章
Poco實例(全局操作) API彙總
Poco基於UI對象的start_gesture()
start_gesture()
滑動手勢。可用於解鎖等複雜手勢操作。
返回:
PendingGestureAction實例
源碼解析:
# 源碼位置:your_python_path\site-packages\poco\proxy.py
def start_gesture(self):
return PendingGestureAction(self.poco, self)
其實這裏start_gesture()只是包了個皮,他實際是返回了一個PendingGestureAction實例,手勢操作也是由PendingGestureAction實現的。
PendingGestureAction源碼:
# 源碼位置:your_python_path\site-packages\poco\gesture.py
class PendingGestureAction(object):
def __init__(self, pocoobj, uiproxy_or_pos):
super(PendingGestureAction, self).__init__()
self.pocoobj = pocoobj
self.track = MotionTrack()
if isinstance(uiproxy_or_pos, (list, tuple)):
self.track.start(uiproxy_or_pos)
else:
self.track.start(uiproxy_or_pos.get_position())
def hold(self, t):
self.track.hold(t)
return self
def to(self, pos):
if isinstance(pos, (list, tuple)):
self.track.move(pos)
else:
uiobj = pos
self.track.move(uiobj.get_position())
return self
def up(self):
self.pocoobj.apply_motion_tracks([self.track])
PendingGestureAction類實例參數中,第1個參數是poco實例。
第2個參數可以是屏幕相對座標或Poco UI對象實例,不過如果是UI對象的話,最終也是通過get_position()獲取到屏幕相對座標。
PendingGestureAction的hold()和to()方法都是對初始化時的MotionTrack類實例積攢手勢軌跡座標。其中to()方法參數支持傳入屏幕相對座標或Poco UI對象實例,不過如果是UI對象的話,最終也是通過get_position()獲取到屏幕相對座標。
__init__、hold()、to()分別調用了MotionTrack類的start()、hold()、move()方法,那我們就繼續看下MotionTrack類的部分源碼:
# 源碼位置:your_python_path\site-packages\poco\utils\track.py
class MotionTrack(object):
def __init__(self, points=None, speed=0.4):
super(MotionTrack, self).__init__()
self.speed = speed
self.timestamp = 0
self.event_points = [] # [ts, (x, y), contact_id], timestamp as arrival time
if points:
for p in points:
self.move(p)
@property
def last_point(self):
if self.event_points:
return self.event_points[-1][1]
return None
def start(self, p):
return self.move(p)
def move(self, p):
if self.last_point:
dt = (Vec2(p) - Vec2(self.last_point)).length / self.speed
self.timestamp += dt
self.event_points.append([self.timestamp, p, 0])
return self
def hold(self, t):
self.timestamp += t
if self.event_points:
self.move(self.last_point)
return self
MotionTrack類就是用來生成滑動軌跡的,start()、hold()、move()方法最終都是把手勢滑動的節點座標計算出來放在了event_points列表。最終滑動時也是根據這個座標列表來執行的。
我們回過頭接着看PendingGestureAction的最後一個方法up(),實際是調用poco實例的apply_motion_tracks(),並把之前的MotionTrack實例傳入(記錄着滑動座標列表)。
最後就是按軌跡執行滑動,看下apply_motion_tracks()源碼:
# 源碼位置:your_python_path\site-packages\poco\pocofw.py
def apply_motion_tracks(self, tracks, accuracy=0.004):
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()方法。
示例:
from airtest.core.api import *
from poco.drivers.unity3d import UnityPoco
auto_setup(__file__)
poco = UnityPoco()
ui1 = poco('測試工程師')
ui2 = poco('小站')
# 按住'測試工程師'1秒,滑到'小站',等待1秒,滑到屏幕中心,等待1秒,擡起
ui1.start_gesture().hold(1).to(ui2).hold(1).to([0.5,0.5]).hold(1).up()
Poco基於全局操作的start_gesture()
start_gesture(pos)
滑動手勢。可用於解鎖等複雜手勢操作。
參數:
pos - 起點
返回:
PendingGestureAction實例
源碼解析:
# 源碼位置:your_python_path\site-packages\poco\pocofw.py
def start_gesture(self, pos):
return PendingGestureAction(self, pos)
全局操作的start_gesture()與UI對象的start_gesture()源碼幾乎一樣,唯一不一樣的就是全局操作的start_gesture()需要傳入一個起始點的屏幕相對座標。
示例:
from airtest.core.api import *
from poco.drivers.unity3d import UnityPoco
auto_setup(__file__)
poco = UnityPoco()
# 滑一個V形狀
poco.start_gesture([0.5, 0.5]).hold(1).to([0.6, 0.6]).hold(1).to([0.7, 0.5]).up()
---------------------------------------------------------------------------------
關注微信公衆號即可在手機上查閱,並可接收更多測試分享~