man*_*sta 24 touch mapkit mkmapview ios mkoverlay
我有一个可能有数百个多边形的MKMapView.iOS7上假设使用MKPolygon和MKPolygonRenderer.
我需要的是一种对用户触摸其中一个多边形的方式.它们代表地图上具有一定人口密度的区域.在iOS6上,MKOverlay被绘制为MKOverlayViews,因此触摸检测更直接.现在使用渲染器我真的不明白这是怎么做的.
我不确定这会有所帮助甚至是相关的,但作为参考,我会发布一些代码:
这会使用mapData将所有MKOverlay添加到MKMapView.
-(void)drawPolygons{
self.polygonsInfo = [NSMutableDictionary dictionary];
NSArray *polygons = [self.mapData valueForKeyPath:@"polygons"];
for(NSDictionary *polygonInfo in polygons){
NSArray *polygonPoints = [polygonInfo objectForKey:@"boundary"];
int numberOfPoints = [polygonPoints count];
CLLocationCoordinate2D *coordinates = malloc(numberOfPoints * sizeof(CLLocationCoordinate2D));
for (int i = 0; i < numberOfPoints; i++){
NSDictionary *pointInfo = [polygonPoints objectAtIndex:i];
CLLocationCoordinate2D point;
point.latitude = [[pointInfo objectForKey:@"lat"] floatValue];
point.longitude = [[pointInfo objectForKey:@"long"] floatValue];
coordinates[i] = point;
}
MKPolygon *polygon = [MKPolygon polygonWithCoordinates:coordinates count:numberOfPoints];
polygon.title = [polygonInfo objectForKey:@"name"];
free(coordinates);
[self.mapView addOverlay:polygon];
[self.polygonsInfo setObject:polygonInfo forKey:polygon.title]; // Saving this element information, indexed by title, for later use on mapview delegate method
}
}
Run Code Online (Sandbox Code Playgroud)
然后有一个委托方法为每个MKOverlay返回一个MKOverlayRenderer:
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
/* ... */
MKPolygon *polygon = (MKPolygon*) overlay;
NSDictionary *polygonInfo = [self.polygonsInfo objectForKey:polygon.title]; // Retrieving element info by element title
NSDictionary *colorInfo = [polygonInfo objectForKey:@"color"];
MKPolygonRenderer *polygonRenderer = [[MKPolygonRenderer alloc] initWithPolygon:polygon];
polygonRenderer.fillColor = [UIColor colorWithRed:[[colorInfo objectForKey:@"red"] floatValue]
green:[[colorInfo objectForKey:@"green"] floatValue]
blue:[[colorInfo objectForKey:@"blue"] floatValue]
alpha:[[polygonInfo objectForKey:@"opacity"] floatValue]];
return polygonRenderer;
/* ... */
}
Run Code Online (Sandbox Code Playgroud)
man*_*sta 26
我做到了
感谢incanus和Anna!
基本上我将一个TapGestureRecognizer添加到MapView,将点击的点转换为地图坐标,浏览我的叠加层并使用CGPathContainsPoint进行检查.
添加TapGestureRecognizer.我做了添加第二个双击手势的技巧,这样当双击缩放地图时,不会触发单击手势.如果有人知道更好的方式,我很高兴听到!
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapTap:)];
tap.cancelsTouchesInView = NO;
tap.numberOfTapsRequired = 1;
UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] init];
tap2.cancelsTouchesInView = NO;
tap2.numberOfTapsRequired = 2;
[self.mapView addGestureRecognizer:tap2];
[self.mapView addGestureRecognizer:tap];
[tap requireGestureRecognizerToFail:tap2]; // Ignore single tap if the user actually double taps
Run Code Online (Sandbox Code Playgroud)
然后,在点击处理程序上:
-(void)handleMapTap:(UIGestureRecognizer*)tap{
CGPoint tapPoint = [tap locationInView:self.mapView];
CLLocationCoordinate2D tapCoord = [self.mapView convertPoint:tapPoint toCoordinateFromView:self.mapView];
MKMapPoint mapPoint = MKMapPointForCoordinate(tapCoord);
CGPoint mapPointAsCGP = CGPointMake(mapPoint.x, mapPoint.y);
for (id<MKOverlay> overlay in self.mapView.overlays) {
if([overlay isKindOfClass:[MKPolygon class]]){
MKPolygon *polygon = (MKPolygon*) overlay;
CGMutablePathRef mpr = CGPathCreateMutable();
MKMapPoint *polygonPoints = polygon.points;
for (int p=0; p < polygon.pointCount; p++){
MKMapPoint mp = polygonPoints[p];
if (p == 0)
CGPathMoveToPoint(mpr, NULL, mp.x, mp.y);
else
CGPathAddLineToPoint(mpr, NULL, mp.x, mp.y);
}
if(CGPathContainsPoint(mpr , NULL, mapPointAsCGP, FALSE)){
// ... found it!
}
CGPathRelease(mpr);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我可以要求已经具有"path"属性并使用它的MKPolygonRenderer,但由于某种原因它总是为零.我确实读过有人说我可以在渲染器上调用invalidatePath并且它确实填充了path属性但它似乎错了,因为在任何多边形中都找不到该点.这就是我从点重建路径的原因.这样我甚至不需要渲染器,只需使用MKPolygon对象.
dav*_*ynn 11
UPDATED(对于Swift 3和4)我不确定为什么人们在mapView已经运行了许多手势识别器时向mapView添加了UIGestureRecognizer.我发现这些方法会抑制mapView的正常功能,特别是点击注释.相反,我建议继承mapView并覆盖touchesEnded方法.然后我们可以使用其他人在这个线程中建议的方法,并使用委托方法告诉ViewController做任何需要做的事情."touches"参数有一组我们可以使用的UITouch对象:
import UIKit
import MapKit
protocol MapViewTouchDelegate: class {
func polygonsTapped(polygons: [MKPolygon])
}
class MyMapViewSubclass: MapView {
weak var mapViewTouchDelegate: MapViewTouchDelegate?
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
if touch.tapCount == 1 {
let touchLocation = touch.location(in: self)
let locationCoordinate = self.convert(touchLocation, toCoordinateFrom: self)
var polygons: [MKPolygon] = []
for polygon in self.overlays as! [MKPolygon] {
let renderer = MKPolygonRenderer(polygon: polygon)
let mapPoint = MKMapPointForCoordinate(locationCoordinate)
let viewPoint = renderer.point(for: mapPoint)
if renderer.path.contains(viewPoint) {
polygons.append(polygon)
}
if polygons.count > 0 {
//Do stuff here like use a delegate:
self.mapViewTouchDelegate?.polygonsTapped(polygons: polygons)
}
}
}
}
super.touchesEnded(touches, with: event)
}
Run Code Online (Sandbox Code Playgroud)
不要忘记将ViewController设置为mapViewTouchDelegate.我还发现为MKPolygon做一个扩展很方便:
import MapKit
extension MKPolygon {
func contains(coordinate: CLLocationCoordinate2D) -> Bool {
let renderer = MKPolygonRenderer(polygon: self)
let mapPoint = MKMapPointForCoordinate(coordinate)
let viewPoint = renderer.point(for: mapPoint)
return renderer.path.contains(viewPoint)
}
}
Run Code Online (Sandbox Code Playgroud)
然后该功能可以更清洁,扩展可能在其他地方有用.再加上它太快了!
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
if touch.tapCount == 1 {
let touchLocation = touch.location(in: self)
let locationCoordinate = self.convert(touchLocation, toCoordinateFrom: self)
var polygons: [MKPolygon] = []
for polygon in self.overlays as! [MKPolygon] {
if polygon.contains(coordinate: locationCoordinate) {
polygons.append(polygon)
}
}
if polygons.count > 0 {
//Do stuff here like use a delegate:
self.mapViewTouchDelegate?.polygonsTapped(polygons: polygons)
}
}
}
super.touchesEnded(touches, with: event)
}
Run Code Online (Sandbox Code Playgroud)
小智 5
我找到了一个类似于@manecosta的解决方案,但它使用现有的Apple API来更轻松地检测交集.
从视图中的点按位置创建MKMapRect.我使用0.000005作为lat/long delta来表示用户的触摸.
CGPoint tapPoint = [tap locationInView:self.mapView];
CLLocationCoordinate2D tapCoordinate = [self.mapView convertPoint:tapPoint toCoordinateFromView:self.mapView];
MKCoordinateRegion tapCoordinateRection = MKCoordinateRegionMake(tapCoordinate, MKCoordinateSpanMake(0.000005, 0.000005));
MKMapRect touchMapRect = MKMapRectForCoordinateRegion(tapCoordinateRection);
Run Code Online (Sandbox Code Playgroud)
搜索所有MapView叠加层并使用'intersectsMapRect:'函数来确定当前叠加层是否与您在上面创建的MapRect相交.
for (id<MKOverlay> overlay in self.mapView.overlays) {
if([overlay isKindOfClass:[MKPolyline class]]){
MKPolyline *polygon = (MKPolyline*) overlay;
if([polygon intersectsMapRect:touchMapRect]){
NSLog(@"found polygon:%@",polygon);
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
7309 次 |
最近记录: |