其他分享
首页 > 其他分享> > Poco API精讲之自定义手势start_gesture()

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()

 

 

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

关注微信公众号即可在手机上查阅,并可接收更多测试分享~

标签:自定义,poco,精讲,pos,start,源码,self,gesture
来源: https://www.cnblogs.com/songzhenhua/p/16339614.html