【问题标题】:Callout from MKPolylineView?来自 MKPolylineView 的标注?
【发布时间】:2012-03-29 18:49:49
【问题描述】:
当一个人触摸 MKPolylineView 时,有什么方法可以显示标注?
我试图添加一个 UITapGestureRecognizer 并在选择器中显示某个坐标的标注。但没有用。有什么建议吗?
以下是我尝试过的方法
- (MKOverlayView *)mapView:(MKMapView *)mapa viewForOverlay:(id <MKOverlay>)overlay
self.polylineView = [[MKPolylineView alloc] initWithPolyline: self.polyline];
self.polylineView.strokeColor = [UIColor blackColor];
self.polylineView.lineWidth = 5.0;
self.polylineView.alpha = 0.7;
UITapGestureRecognizer *touchOnView = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(addBubble:)];
[touchOnView setNumberOfTapsRequired:1];
[touchOnView setNumberOfTouchesRequired:1];
[self.polylineView addGestureRecognizer:touchOnView];
【问题讨论】:
标签:
ios
mkmapview
mkannotation
mkoverlay
【解决方案1】:
非常有趣的问题 - 我什至从未想过将手势识别器放在地图叠加层上。通过一些实验,我已经验证可以检测到对MKPolylineView 的点击。正如您所发现的,点击手势不适用于地图叠加层。因此,我将轻击手势放在MKMapView 而不是MKPolylineView 上。然后处理水龙头:
- (void)handleTapGesture:(UIGestureRecognizer*)gestureRecognizer
{
if (measureLine != nil)
{
UIView* hitView = [self.polylineView hitTest:[gestureRecognizer locationInView:self.polylineView] withEvent:nil];
}
}
如果您的水龙头在MKPolylineView 之外,hitView 将为 nil,如果水龙头在内部,则为 self.polylineView。
但是,这可能并不如您所愿。对于水平和垂直线,它完美地工作,因为底层视图的大小与线的大小大致相同。但是对于 45 度线,底层视图必须比线大得多,因为它是轴对齐边界框 (AABB)。如果您考虑 45 度线,仅使用水平线和垂直线将其包围起来,您最终会得到一个很大的区域 - 比您想要检测到的敲击要大得多。
例如
--------
| / |
| / |
| / |
| / |
|/ |
--------
但是使用点击手势或点击测试将始终导致识别这些 AABB 内的点击。因此,无论您尝试将手势附加到何处 - 例如到MKPolylineView 或MKMapView,你会得到虚假的结果。对于较长的线,问题会变得更糟 - 如果您想象一条线从地图视图的右上角到左下角,那么您需要将其包围的 AABB 将覆盖地图视图的整个区域,这意味着点击左上角或右下角将被解释为点击MKPolylineView。
为了解决这个问题,我建议采用以下方法:
- 在地图视图上使用点击手势识别器
- 在您处理水龙头的方法中:
- 将屏幕点击位置转换为地图坐标
- 循环遍历每条折线(除非您只有 1 条)
- 对于折线中的每个点,选取将该点连接到下一个点的线段,并计算地图坐标与这条线的距离。使用三角函数来计算。
- 如果距离非常接近此段,则停止检查其余段并处理您想要显示的任何标注等
- 如果距离不近,则移动到下一个点以及将其连接到下一个点的线段
无论多段线的长度或它们的角度如何,都可以保证这种方法有效。没有 AABB 的担忧。缺点是所有这些距离计算可能在计算上很昂贵 - 因此,如果您的折线由大量点组成,或者如果您有大量折线,那么您可能无法进行所有这些计算在不阻止 UI 响应的情况下,这意味着您需要将其移动到后台线程中。如果你只有几条折线,和/或它们由几个点组成,那么你会没事的。