Poco API精讲之缩放pinch()

上期回顾:Poco API精讲之滚动scroll()


以下基于
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")  # 向外放大

 

 

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

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

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