Poco API精講之自定義手勢start_gesture()

上期回顧: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()

 

 

---------------------------------------------------------------------------------

關注微信公衆號即可在手機上查閱,並可接收更多測試分享~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章