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")  # 向外放大

 

 

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

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

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