最近实现了这样一个需求:当点击一个全屏的 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 的点击位置获取,从而实现该位置的转发处理。
评论