最近实现了这样一个需求:当点击一个全屏的 modal view 时,这个事件同时要“转发”给 modal view 下面一层中的 action view。
分解为技术需求就是获取到 modal view 的 touch 点,然后交给 action view 去处理。
下面是我实现过程中的两个方案。
实现一:touchesBegan:withEvent:
使用 UIResponder 的touchesBegan:withEvent:来获取 touch 点坐标,然后转交给 action view 的持有者,来触发对应的 action。
具体实现步骤:
在 ModalView 中加入对 touch 事件的监测
// 由于ModalButton是全屏的,屏幕上绝大部分位置的touch事件都会被如下回调监测到- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ // 计算出touch事件对应的点 UITouch *aTouch = [touches anyObject]; CGPoint point = [aTouch locationInView:self]; // point.x and point.y have the coordinates of the touch // 将该点记录下来,便于后续通过delegate或其它方式通知给controller self.lastTapPoint = point;}
// 如果只是想拦截touch手势点,而不是pan手势点,在这里要将位置点清空- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ // If pan or move, clear point self.lastTapPoint = CGPointZero;}
复制代码
将 lastTapPoint 通知给 ActionView 或其持有者
判断该点是否在 ActionView 的 frame 内
// 如下代码示例中,我需要判断point是否在imageView或label内- (BOOL)checkPointInsideMenuItem:(UIView *)container point:(CGPoint)point { UIView *actionView1 = ...; // 注意:这里一定要对point做下坐标系转换 CGPoint aPoint = [container convertPoint:point toView:actionView1]; if (imageView && [actionView1 pointInside:aPoint withEvent:nil]) { return YES; } UIView *actionView2 = ...; aPoint = [container convertPoint:point toView:actionView2]; if (actionView2 && [actionView2 pointInside:aPoint withEvent:nil]) { return YES; } return NO;}
复制代码
UIView 的convertPoint:toView: 可以很方便的将当前 view 中的点,转换为目标 view 坐标系中的点。
测试结果:
该实现存在明显 bug:有很大概率touchesBegan:withEvent:不能被系统回调,尝试了不少设置,也不能解决。虽然回调不能触发,但是 ModalView 的 tap gesture 却可以触发到 selector 函数。
实现二:UIGestureRecognizerDelegate
基于实现一的发现,将目光集中到 UITapGestureRecognizer 上。查阅文档,这个 delegate 可以让开发者可以微调手势行为。经过一些测试,可以在gestureRecognizerShouldBegin:这个回调中来获取 touch point。
具体实现步骤:
给 ModalView 的UITapGestureRecognizer设置UIGestureRecognizerDelegate
在 delegate 中获取 tap 点:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;{ CGPoint point = [gestureRecognizer locationOfTouch:0 inView:self.modalView.superview]; self.lastTapPoint = point; return YES;}
复制代码
checkPointInsideMenuItem的实现不用变化
经过最终测试,这个方法可以很好的实现 ModalView 的点击位置获取,从而实现该位置的转发处理。
评论