Poco API精讲之缩放pinch()
以下基于
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") # 向外放大
---------------------------------------------------------------------------------
关注微信公众号即可在手机上查阅,并可接收更多测试分享~