手势识别器并不总是被触发
Gesture Recognizer Not Always Triggered
我正在尝试使地图注释的标注气泡可点击(我希望标题可点击)。根据我所见,没有好的方法可以做到这一点,所以我在地图上实现了一个手势识别器,这样我就可以进行点击测试以确定标注是否已被点击。大多数时候它工作正常,但有时手势识别器无法触发。
这是我的代码
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UITapGestureRecognizer* calloutRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(calloutTapped:)];
calloutRecognizer.cancelsTouchesInView = false;
[self.mapView addGestureRecognizer:calloutRecognizer];
}
- (void)calloutTapped:(UITapGestureRecognizer *)gestureRecognizer
{
CGPoint hitPoint = [gestureRecognizer locationInView:self.mapView];
UIView *tappedView = [self.mapView hitTest:hitPoint withEvent:nil];
// This passthrough button ends up consuming events in the callout
// There seems to be no way to target it explicitly so we must check the class name of the view
if([NSStringFromClass([tappedView class]) isEqualToString: @"_MKSmallCalloutPassthroughButton"]){
if(self.mapView.selectedAnnotations.count > 0 ){
[self clinicTappedForClinic:[self getClinicForAnnotation :self.mapView.selectedAnnotations[0]]];
}
}
}
我正在使用 iPhone 7 模拟器进行测试
有两种方法可以检测用户与注释视图的交互。常用技术是为 MKAnnotationView
定义标注(在典型地图应用程序中点击图钉时看到的标准小弹出气泡)。然后您在标准 viewForAnnotation
方法中为您的注释创建注释视图:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
通过这样做,你会得到一个标注,但你添加了一个正确的附件,在我上面的例子中,这是一个披露指示器。这样,他们点击您的注释视图(在我上面的示例中,地图上的一个图钉),他们看到标注,当他们点击该标注的右侧附件(本例中的小披露指示器)时,您的 calloutAccessoryControlTapped
被调用(在我下面的示例中,对某个详细视图控制器执行 segue):
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
// tap action
}
这是小 iPhone 屏幕上非常典型的用户体验。
但是,如果您不喜欢该用户体验并且不想要标准标注,而是希望发生其他事情,您可以定义 MKAnnotationView
以便不显示标注,而是截取它并执行其他操作(例如,在 iPad 地图应用程序上,您可能会显示一些更复杂的弹出窗口而不是标准标注)。例如,您可以让 MKAnnotationView
不显示标注:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"];
annotationView.canShowCallout = NO;
return annotationView;
}
但是您随后可以手动处理 didSelectAnnotationView
以检测用户何时点击了您的 MKAnnotationView
,在此示例中显示了弹出窗口:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
[mapView deselectAnnotation:view.annotation animated:YES];
DetailsViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"DetailsPopover"];
controller.annotation = view.annotation;
self.popover = [[UIPopoverController alloc] initWithContentViewController:controller];
self.popover.delegate = self;
[self.popover presentPopoverFromRect:view.frame
inView:view.superview
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
如果你尝试使用 UITapGestureRecognizer 那么你可以参考:
How can I catch tap on MapView and then pass it to default gesture recognizers?
将委托添加到 tapGestureRecognizer:
//add <UIGestureRecognizerDelegate> to .h
//add this where you create tapGestureRecognizer...
tapGestureRecognizer.delegate = self;
// check tapGestureRecognizer working or not properly
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
我正在尝试使地图注释的标注气泡可点击(我希望标题可点击)。根据我所见,没有好的方法可以做到这一点,所以我在地图上实现了一个手势识别器,这样我就可以进行点击测试以确定标注是否已被点击。大多数时候它工作正常,但有时手势识别器无法触发。
这是我的代码
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UITapGestureRecognizer* calloutRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(calloutTapped:)];
calloutRecognizer.cancelsTouchesInView = false;
[self.mapView addGestureRecognizer:calloutRecognizer];
}
- (void)calloutTapped:(UITapGestureRecognizer *)gestureRecognizer
{
CGPoint hitPoint = [gestureRecognizer locationInView:self.mapView];
UIView *tappedView = [self.mapView hitTest:hitPoint withEvent:nil];
// This passthrough button ends up consuming events in the callout
// There seems to be no way to target it explicitly so we must check the class name of the view
if([NSStringFromClass([tappedView class]) isEqualToString: @"_MKSmallCalloutPassthroughButton"]){
if(self.mapView.selectedAnnotations.count > 0 ){
[self clinicTappedForClinic:[self getClinicForAnnotation :self.mapView.selectedAnnotations[0]]];
}
}
}
我正在使用 iPhone 7 模拟器进行测试
有两种方法可以检测用户与注释视图的交互。常用技术是为 MKAnnotationView
定义标注(在典型地图应用程序中点击图钉时看到的标准小弹出气泡)。然后您在标准 viewForAnnotation
方法中为您的注释创建注释视图:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
通过这样做,你会得到一个标注,但你添加了一个正确的附件,在我上面的例子中,这是一个披露指示器。这样,他们点击您的注释视图(在我上面的示例中,地图上的一个图钉),他们看到标注,当他们点击该标注的右侧附件(本例中的小披露指示器)时,您的 calloutAccessoryControlTapped
被调用(在我下面的示例中,对某个详细视图控制器执行 segue):
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
// tap action
}
这是小 iPhone 屏幕上非常典型的用户体验。
但是,如果您不喜欢该用户体验并且不想要标准标注,而是希望发生其他事情,您可以定义 MKAnnotationView
以便不显示标注,而是截取它并执行其他操作(例如,在 iPad 地图应用程序上,您可能会显示一些更复杂的弹出窗口而不是标准标注)。例如,您可以让 MKAnnotationView
不显示标注:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"];
annotationView.canShowCallout = NO;
return annotationView;
}
但是您随后可以手动处理 didSelectAnnotationView
以检测用户何时点击了您的 MKAnnotationView
,在此示例中显示了弹出窗口:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
[mapView deselectAnnotation:view.annotation animated:YES];
DetailsViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"DetailsPopover"];
controller.annotation = view.annotation;
self.popover = [[UIPopoverController alloc] initWithContentViewController:controller];
self.popover.delegate = self;
[self.popover presentPopoverFromRect:view.frame
inView:view.superview
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
如果你尝试使用 UITapGestureRecognizer 那么你可以参考: How can I catch tap on MapView and then pass it to default gesture recognizers?
将委托添加到 tapGestureRecognizer:
//add <UIGestureRecognizerDelegate> to .h
//add this where you create tapGestureRecognizer...
tapGestureRecognizer.delegate = self;
// check tapGestureRecognizer working or not properly
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}