标注在iOS7放大后打开错误的视图 [英] Callout opening wrong view after zoom in iOS7

查看:78
本文介绍了标注在iOS7放大后打开错误的视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序中的所有内容均正常运行,但有一件事情:放大和缩小后,要查看整个地图,有些标注会打开错误的detailview. 我不知道我是否缺少一些代码. 使用适用于iOS7的Xcode 5.1.1. 这是我目前所拥有的:

Everything is working fine in my app except for one thing: after zooming in and zooming back out, to see the whole map, some callouts open the wrong detailview. I don't know if I'm missing some code or else. Using Xcode 5.1.1 for iOS7. This is what I've got at the moment:

Annotation.h

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface Annotation: NSObject <MKAnnotation>

@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;

@end

Annotation.m

#import "Annotation.h"

@implementation Annotation
@synthesize coordinate,title,subtitle;

@end

MapView.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>

@interface Nameofthemap : UIViewController <MKMapViewDelegate>

@property (strong, nonatomic) IBOutlet MKMapView *Nameofthemap;

@end

MapView.m

#import "MapView.h"
#import "Annotation.h"
#import "InfoViewController.h"
#import "InfoTwoViewController.h"

@interface MapView ()
@property (nonatomic, strong) IBOutlet InfoViewController *InfoViewController;

@property (nonatomic, strong) IBOutlet InfoTwoViewController *InfoTwoViewController;

@end

#define PLACE1_LATITUDE 43.777130;
#define PLACE2_LONGITUDE 10.790018;

#define PLACE2_LATITUDE 43.81471237;

#define PLACE2_LONGITUDE 10.67472765;

@implementation MapView

- (IBAction)changeMapType:(id)sender {
    if (_MapView.mapType == MKMapTypeHybrid)
    _MapView.mapType = MKMapTypeStandard;
else
    _MapView.mapType = MKMapTypeHybrid;
}

- (void)viewDidLoad
{
[super viewDidLoad];

[self gotoLocation];

_MapView.showsUserLocation = YES;


}
- (void)gotoLocation
{
MKCoordinateRegion newRegion;

newRegion.center.latitude = PLACE1_LATITUDE;
newRegion.center.longitude = PLACE2_LONGITUDE;

newRegion.span.latitudeDelta = 0.25f;
newRegion.span.longitudeDelta = 0.25f;

[self.MapView setRegion:newRegion animated:YES];

NSMutableArray * locations = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location;
Annotation *myAnn;

Annotation *myAnn2;

//Place1 annotation
myAnn = [[Annotation alloc] init];
location.latitude = PLACE1_LATITUDE;
location.longitude = PLACE1_LONGITUDE;
myAnn.coordinate = location;
myAnn.title = @"Name of the place";
myAnn.subtitle = @"Details";
[locations addObject:myAnn];

//Place2 annotation
myAnn2 = [[Annotation alloc] init];
location.latitude = PLACE2_LATITUDE;
location.longitude = PLACE2_LONGITUDE;
myAnn2.coordinate = location;
myAnn2.title = @"Name of place two";
myAnn2.subtitle = @"Details";

[locations addObject:myAnn2];

[self->_MapView addAnnotations:locations];

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view     calloutAccessoryControlTapped:(UIControl *)control{

}

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)myAnn {
if ([myAnn isKindOfClass:[MKUserLocation class]])
{
    ((MKUserLocation *)myAnn).title = @"Your position";
    return nil;
}
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView  dequeueReusableAnnotationViewWithIdentifier:@"pinView"];
if (!pinView) {
    pinView = [[MKPinAnnotationView alloc] initWithAnnotation:myAnn reuseIdentifier:@"pinView"];
    pinView.pinColor = MKPinAnnotationColorRed;
    pinView.canShowCallout = YES;

    UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    if ([[myAnn title] isEqualToString:@"Name of the place"]){
        [rightButton addTarget:self  action:@selector(myAnnClicked:)forControlEvents:UIControlEventTouchUpInside];
    }
    if ([[myAnn title] isEqualToString:@"Name of place two"]){
        [rightButton addTarget:self action:@selector(myAnn2Clicked:)forControlEvents:UIControlEventTouchUpInside];

    }
pinView.rightCalloutAccessoryView = rightButton;
}
    return pinView;
}

-(IBAction)myAnnClicked:(id)sender
{
InfoViewController *info = [[InfoViewController alloc]init];
[self.navigationController pushViewController:info animated:YES];
}
-(IBAction)myAnn2Clicked:(id)sender
{
InfoTwoController *info2 = [[InfoTwoController alloc]init];
[self.navigationController pushViewController:info2 animated:YES];

}
@end

推荐答案

这是注释视图重用问题.

It's an annotation view re-use issue.

viewForAnnotation中,仅在创建视图时设置按钮目标(如果dequeueReusableAnnotationViewWithIdentifier返回nil).

In viewForAnnotation, the button targets are only being set when creating a view (if dequeueReusableAnnotationViewWithIdentifier returns nil).

但是,如果dequeueReusableAnnotationViewWithIdentifier返回以前使用的视图,则按钮目标仍然是为以前使用该视图的注释设置的内容.

But if dequeueReusableAnnotationViewWithIdentifier returns a previously-used view, the button target is still whatever was set for the annotation that used the view before.

先前的注释可能与当前的注释不同.

That previous annotation may not be the same as the current annotation.

因此,注释两个"可能会重新使用最初为注释一个"创建的视图,然后点击已创建的按钮将显示一个"而不是两个"的信息.

So it's possible for annotation "two" to re-use a view that was originally created for annotation "one" and tapping on the already-created button shows the info for "one" instead of "two".

要解决此问题,应该做两件事:

To fix this, two things should be done:

  1. 如果dequeueReusableAnnotationViewWithIdentifier返回视图(如果pinView不是nil),则代码必须将视图的annotation属性更新为当前注释.
  2. 必须设置按钮目标,是要创建新视图还是要重新使用出列视图.最简单的方法是将按钮的创建/设置移至主if之后且return之前.
  1. If dequeueReusableAnnotationViewWithIdentifier returns a view (if pinView is not nil), the code must update the view's annotation property to the current annotation.
  2. The button target must be set whether a new view is being created or a dequeued view is being re-used. The easiest way to do this is to move the button creation/setting after the main if and just before the return.

更新后的viewForAnnotation看起来像这样:

The updated viewForAnnotation would look like this:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)myAnn {
    if ([myAnn isKindOfClass:[MKUserLocation class]])
    {
        ((MKUserLocation *)myAnn).title = @"Your position";
        return nil;
    }

    MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView  dequeueReusableAnnotationViewWithIdentifier:@"pinView"];
    if (!pinView) {
        pinView = [[MKPinAnnotationView alloc] initWithAnnotation:myAnn reuseIdentifier:@"pinView"];
        pinView.pinColor = MKPinAnnotationColorRed;
        pinView.canShowCallout = YES;
    }
    else
    {
        //1. Re-using a view, update which annotation it's being used for now
        pinView.annotation = myAnn;
    }

    //2. Now pinView is either a new view or re-used view.
    //Set its button target based on current annotation...

    UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    if ([[myAnn title] isEqualToString:@"Name of the place"]){
        [rightButton addTarget:self  action:@selector(myAnnClicked:)forControlEvents:UIControlEventTouchUpInside];
    }
    if ([[myAnn title] isEqualToString:@"Name of place two"]){
        [rightButton addTarget:self action:@selector(myAnn2Clicked:)forControlEvents:UIControlEventTouchUpInside];

    }
    pinView.rightCalloutAccessoryView = rightButton;

    return pinView;
}


顺便说一句,不要为每个注释创建单独的方法(这可能会很乏味),而应使用地图视图的calloutAccessoryControlTapped委托方法.

By the way, instead of creating separate methods for each annotation (which can get tedious), use the map view's calloutAccessoryControlTapped delegate method instead.

事实上,现在,地图视图正在调用您的自定义方法和calloutAccessoryControlTapped委托方法(目前没有代码).

In fact, right now, the map view is calling both your custom methods and the calloutAccessoryControlTapped delegate method (in which there's no code currently).

在委托方法中,可以通过view.annotation访问被点击的注释.

In the delegate method, the annotation tapped is accessible via view.annotation.

因此,在viewForAnnotation中,您只需执行以下操作:

So in viewForAnnotation, you would just do this:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)myAnn {
    if ([myAnn isKindOfClass:[MKUserLocation class]])
    {
        ((MKUserLocation *)myAnn).title = @"Your position";
        return nil;
    }

    MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView  dequeueReusableAnnotationViewWithIdentifier:@"pinView"];
    if (!pinView) {
        pinView = [[MKPinAnnotationView alloc] initWithAnnotation:myAnn reuseIdentifier:@"pinView"];
        pinView.pinColor = MKPinAnnotationColorRed;
        pinView.canShowCallout = YES;
        pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    }
    else
    {
        pinView.annotation = myAnn;
    }

    return pinView;
}

然后在calloutAccessoryControlTapped委托方法中,您可以执行以下操作:

Then in the calloutAccessoryControlTapped delegate method, you can do something like this:

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{

    if ([view.annotation isKindOfClass:[Annotation class]])
    {
        Annotation *myAnn = (Annotation *)view.annotation;

        id vcToPush = nil;

        if ([[myAnn title] isEqualToString:@"Name of the place"]) {
            vcToPush = [[InfoViewController alloc]init];
        }
        else if ([[myAnn title] isEqualToString:@"Name of place two"]) {
            vcToPush = [[InfoTwoController alloc]init];
        }

        [self.navigationController pushViewController:vcToPush animated:YES];
    }
}

然后删除myAnnClickedmyAnn2Clicked方法.

最好为每个注释创建一个通用的信息"视图控制器,而不是单独创建一个视图控制器.

You would also be much better off creating a generic "Info" view controller instead of a separate one for each annotation.

其他一些无关的东西:

  • 不要在#define行的末尾加上分号
  • 您已定义PLACE2_LONGITUDE两次
  • newRegion.center使用的是PLACE2_LONGITUDE而不是PLACE1_LONGITUDE
  • Don't put a semi-colon at the end of the #define lines
  • You've defined PLACE2_LONGITUDE twice
  • newRegion.center is using PLACE2_LONGITUDE instead of PLACE1_LONGITUDE

这篇关于标注在iOS7放大后打开错误的视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆