【问题标题】:MKPolygon ontouch detailviewMKPolygon ontouch detailview
【发布时间】:2023-03-24 16:44:01
【问题描述】:

我根据坐标创建了一个MKMapViewMKPolygons。地图上有多个多边形(查看here 以了解我正在重新创建为应用程序的示例)。

我想要做的是当用户触摸多边形时,它会打开一个弹出视图,其中包含有关位置的信息。此信息当前存储在带有坐标的 plist 文件中。

到目前为止,我能够获取触摸事件并打印到多边形被触摸的日志。

我的问题是:
MKPolygonView 可以像 MKAnnotationView 一样使用,一旦用户点击 pin,就会弹出更多关于当前位置的信息?

我想对多边形视图做同样的事情。触摸时,用户将看到有关存储在 plist 中的位置的更多信息。如果可能的话,最好的方法是什么?

我当前的代码如下。

#import "outagemapViewController.h"
#import "MyAnnotation.h"
#import "WildcardGestureRecognizer.h"
#define METERS_PER_MILE 46309.344
@interface outagemapViewController ()

@end

@implementation outagemapViewController
- (void)viewDidLoad {

outages = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"outages"ofType:@"plist"]];


for (NSDictionary *coloredAreas in outages) {
   coordinateData = coloredAreas[@"coords"];
test = coloredAreas[@"outages"];

    NSLog(@"test %@", test);
    coordsLen = [coordinateData count];
      NSLog(@"coords %d", coordsLen);
    CLLocationCoordinate2D coords[coordsLen];
    for (i=0; i < coordsLen; i++) {
        NSString *lat = coordinateData[i];
        NSArray *latt = [lat componentsSeparatedByString:@","];
        double latitude = [[latt objectAtIndex:0] doubleValue];
        double longitude = [[latt objectAtIndex:1] doubleValue];
       coords[i] = CLLocationCoordinate2DMake(latitude, longitude);

    }


 MKPolygon* poly2 = [MKPolygon polygonWithCoordinates:coords count:coordsLen];
 poly2.title=@"test";
 [self.mapView addOverlay:poly2];
 }
 }
 - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
{
    if ([overlay isKindOfClass:[MKPolygon class]])
    {

        MKPolygonView*    aView = [[MKPolygonView alloc] initWithPolygon:(MKPolygon*)overlay];

        int numbers = [test intValue];

        if(numbers >= 10){
            aView.fillColor = [[UIColor greenColor] colorWithAlphaComponent:0.6];
            aView.strokeColor = [[UIColor greenColor] colorWithAlphaComponent:1.0];
            aView.lineWidth = 3;
        }else if(numbers < 10){
            aView.fillColor = [[UIColor yellowColor] colorWithAlphaComponent:0.6];
            aView.strokeColor = [[UIColor yellowColor] colorWithAlphaComponent:1.0];
            aView.lineWidth = 3;

                    }

        return aView;
    }


    return nil;
}
 }

-(void)viewWillAppear:(BOOL)animated{
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = 35.20418;
zoomLocation.longitude = -89.86862;

MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation,         0.5*METERS_PER_MILE, 0.5*METERS_PER_MILE);

[_mapView setRegion:viewRegion animated:YES];

WildcardGestureRecognizer * tapInterceptor = [[WildcardGestureRecognizer alloc] init];
tapInterceptor.touchesBeganCallback = ^(NSSet * touches, UIEvent * event) {
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self.mapView];

    CLLocationCoordinate2D coord = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
    MKMapPoint mapPoint = MKMapPointForCoordinate(coord);
    for (id overlay in self.mapView.overlays)
    {
        if ([overlay isKindOfClass:[MKPolygon class]])
        {
            MKPolygon *poly = (MKPolygon*) overlay;
            id view = [self.mapView viewForOverlay:poly];
            if ([view isKindOfClass:[MKPolygonView class]])
            {
                MKPolygonView *polyView = (MKPolygonView*) view;
                CGPoint polygonViewPoint = [polyView pointForMapPoint:mapPoint];
                BOOL mapCoordinateIsInPolygon = CGPathContainsPoint(polyView.path, NULL, polygonViewPoint, NO);
                if (mapCoordinateIsInPolygon) {
                   // debug(@"hit!");
                    NSLog(@"hit");
                } else {
                     NSLog(@"miss");
                }
            }
        }
    }

};
[self.mapView addGestureRecognizer:tapInterceptor];
}

- (void)didReceiveMemoryWarning
{
 [super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

@end

【问题讨论】:

  • 具体问题是什么?命中检测是否有效?
  • 没有像注释那样的内置标注视图。您必须创建一个自定义 UIView 并执行 addSubview 或自定义 UIViewController 并呈现/推送它。
  • 啊。非常感谢你。昨天我对此感到非常沮丧,我想我忘了问真正的问题。 1+ 为您服务,即使它已关闭。

标签: iphone objective-c ios uigesturerecognizer mkoverlay


【解决方案1】:

不幸的是,对于叠加层,没有像注释那样的内置触摸检测和标注视图。

您必须像已经在做的那样手动进行触摸检测(看起来应该可以)。
(更不幸的是,直接将手势识别器添加到覆盖视图中是行不通的——您必须将其添加到整个地图中,然后检查触摸点是否在任何覆盖中。)

对于覆盖标注视图,一旦检测到覆盖上的触摸,您可以创建自定义UIView 并执行addSubview。我建议将其添加到地图而不是覆盖视图中,您也许可以使用您已经在计算的CGPoint point 来确定自定义标注视图的框架。

您可能还希望保留对覆盖图标注视图的 ivar/属性引用,以便在用户点击另一个覆盖图而另一个覆盖图的标注已经显示时可以轻松删除和重新添加它。

另一个可能更容易的选项是创建自定义UIViewController 并呈现或推送它。显示它的具体细节取决于您使用的是导航控制器和/或情节提要。

如果您的应用也是为 iPad 构建的,您还可以使用 UIPopoverController 显示“标注”。
有关代码示例,请参见 How do I display a UIPopoverView as a annotation to the map view? (iPad)(它带有注释,但您应该能够对其进行调整以适应覆盖)。


确定点击了哪个覆盖后,您需要显示原始数据源(outages 数组)中的相关数据。现在,创建并添加了覆盖,但没有对原始数据对象的引用(outages 数组中的中断字典)。

(子类化MKPolygon 以添加自定义属性has issues and workarounds 并创建一个完全自定义的MKOverlay 类引入了许多其他额外的工作。)

对于您当前的数据源结构,一个简单、快速(并且有点粗略)的选项是将覆盖的title 属性设置为与覆盖关联的中断对象的outages 数组中的索引。由于title 属性是NSString 并且数组索引是整数,我们将其转换为字符串:

NSUInteger outageIndex = [outages indexOfObject:coloredAreas];
poly2.title = [NSString stringWithFormat:@"%d", outageIndex];
[self.mapView addOverlay:poly2];

viewForOverlay 中,您似乎正在使用test(来自中断对象)来确定多边形的颜色。外部声明/设置的test 变量的值不一定与当前正在调用委托方法的overlay 同步(映射可以为同一个叠加层多次调用viewForOverlay,不一定在命令你添加它们)。您必须根据overlay 参数的某些属性来检索中断对象。由于我们将覆盖的 title 属性设置为中断的索引:

//int numbers = [test intValue];  <-- remove this line

int outageIndex = [overlay.title intValue];
NSDictionary *outageDict = [outages objectAtIndex:outageIndex];
id outageNumbersObject = outageDict[@"outages"]; 
//replace id above with actual type
//can't tell from code in question whether it's NSString or NSNumber 
int numbers = [outageNumbersObject intValue];

//use "numbers" to set polygon color...

最后,当一个覆盖被点击时,您使用与viewForOverlay 相同的方法来获取中断对象:

if (mapCoordinateIsInPolygon) {
    int outageIndex = [overlay.title intValue];
    NSDictionary *outageDict = [outages objectAtIndex:outageIndex];
    NSLog(@"hit, outageDict = %@", outageDict);
    //show view with info from outageDict...
} 

【讨论】:

  • 嗨安娜,你能给我一个例子,上面的代码是如何实现视图和子视图的。我尝试 NSLog 字典的输出,但它只显示最后一条记录。
  • 您尝试的确切 NSLog 是什么?也许您的问题是您无法判断覆盖是针对哪个中断?在 outages 数组中,每个对象是否都有一些与之关联的唯一字符串 id?您可以将叠加层的 title 设置为该唯一字符串,然后查找与该 ID 关联的中断对象。
  • 是的,这就是我遇到的问题。我有一个与每次中断相关联的中断编号,但我无法确定是什么中断被窃听。你能举例说明我应该做什么吗?
  • @Anna 和 Dwill 您可能会讨厌这种方法,但是您可以通过使用“addAnnotations”添加它们来实现将多边形作为可点击标注的理想结果。我绝不推荐这个,但认为它很有趣。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多