MapView中的AnnotationView,从mysql数据库中检索不同的图像

时间:2013-10-04 19:56:43

标签: ios objective-c mkmapview mkannotation mkannotationview

我有一个viewController(带有mapView),它包含在tabBarController中(我的viewController名为MapViewController,是TabBarController的一部分)。

我的TabBarController包含在navigationController中。

我创建了(通过委托方法MKMapViewDelegate)添加到地图的annotationView。我允许标注显示标题和副标题。标题和副标题取自对我的数据库的查询。从这些查询中我得到标题,详细信息,ID(字符串版本)和图像。

我在每个注释的标注中设置标题和副标题没有问题。

但是当我将每个标注的图像设置为LeftCalloutAccessoryView时,系统会给我提供相同的图像。

当我去点击RightCalloutAccessoryView(这是一个推送到另一个viewController的按钮)时,它应该打开(如此推送)作为一个新窗口navigationController,给我一个错误的ID(另一个注释的ID)和因此新窗口中的细节有误。

我知道也许可以解释它,所以有点难以理解,但是这里是代码:

    + (CGFloat)annotationPadding;
    {
        return 10.0f;
    }

    + (CGFloat)calloutHeight;
    {
        return 40.0f;
    }


    - (void)viewDidLoad
    {
        [super viewDidLoad];
        [_mapView setDelegate:self];
        _arrPosters = [[NSMutableArray alloc] init];
        _script = [[DBGMScr alloc] init]; //Is a class that provides script database connection
//With fieldsRequest I get the array with the field results sought
        _arrID = [[NSMutableArray alloc] initWithArray:[_script fieldsRequest:@"SELECT ID FROM Event ORDER BY DateTime DESC"]];
        _arrEventNames = [[NSMutableArray alloc] initWithArray:[_script fieldsRequest:@"SELECT Name FROM Event ORDER BY DateTime DESC"]];
        _arrEventLatitude = [[NSMutableArray alloc] initWithArray:[_script fieldsRequest:@"SELECT Latitude FROM Event ORDER BY DateTime DESC"]];
        _arrEventLongitude = [[NSMutableArray alloc] initWithArray:[_script fieldsRequest:@"SELECT Longitude FROM Event ORDER BY DateTime DESC"]];
        _arrEventDescription = [[NSMutableArray alloc] initWithArray:[_script fieldsRequest:@"SELECT Description FROM Event ORDER BY DateTime DESC"]];

        for (int i = 0; i < [_arrID count]; i++) {

//With getPoster I get the poster for the event (located on the server) by using a script (it works perfectly), and add it to the array of posters
        UIImage *poster = [_script getPoster:_arrID[i]];


            [_arrPosters insertObject:poster atIndex:i];
        }

        for (int i = 0; i < [_arrID count]; i++) {


            MKPointAnnotation *aAnnotationPoint = [[MKPointAnnotation alloc] init];
            CLLocationCoordinate2D theCoordinate;
            theCoordinate.latitude = [_arrEventLatitude[i] doubleValue];
            theCoordinate.longitude = [_arrEventLongitude[i] doubleValue];
            aAnnotationPoint.coordinate = theCoordinate;
            aAnnotationPoint.title = _arrEventNames[i];

            aAnnotationPoint.subtitle = _arrEventDescription[i];

            // Add the annotationPoint to the map
            [_mapView addAnnotation:aAnnotationPoint];

        }

    }


    #pragma mark - MKMapViewDelegate



    -(MKAnnotationView*)mapView:(MKMapView*)mapView viewForAnnotation:(id<MKAnnotation>)annotation {

        CGRect myRect = CGRectMake(-20, -20, 40, 40);

        EventAnnotationView *viewAnno = [[EventAnnotationView alloc] initWithFrame:myRect];

        viewAnno.canShowCallout = YES;
        UIButton* rightButton = [UIButton buttonWithType:
                                 UIButtonTypeDetailDisclosure];
        viewAnno.rightCalloutAccessoryView = rightButton;
        UIImageView *iconView = [[UIImageView alloc] initWithFrame:myRect];
        iconView.image = defaultImage; //defaultImage for now, but I want to show a different image for each annotation
        viewAnno.leftCalloutAccessoryView = iconView;
        NSString *viewTitle = [viewAnno.annotation title];

        return viewAnno;
    }


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

        EventViewerViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"EventViewer"];
        [self.navigationController pushViewController:controller animated:YES];
        NSDictionary *selection = @{@"ID" : _arrID[_eventIndex] //but it get an incorrect ID,
                                    @"eventName" : _arrEventNames[_eventIndex]};

        [controller setValue:selection forKey:@"selection"];
    }

    -(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
    {
    //_eventIndex is an NSInteger declared in file .h
        _eventIndex = [_mapView.annotations indexOfObject:view.annotation];


    }

EventAnnotationView是MKAnnotationView的子类:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // make sure the x and y of the CGRect are half it's
        // width and height, so the callout shows when user clicks
        // in the middle of the image
        CGRect  viewRect = CGRectMake(-20, -20, 40, 40);
        UIImageView* imageView = [[UIImageView alloc] initWithFrame:viewRect];

        // keeps the image dimensions correct
        // so if you have a rectangle image, it will show up as a rectangle,
        // instead of being resized into a square
        imageView.contentMode = UIViewContentModeScaleAspectFit;

        _imageView = imageView;

        [self addSubview:imageView];
    }
    return self;
}

- (void)setImage:(UIImage *)image
{
    // when an image is set for the annotation view,
    // it actually adds the image to the image view
    _imageView.image = image;
}

1 个答案:

答案 0 :(得分:2)

这里有几个问题,但首先回答你的两个主要问题:

  1. 要为每个注释将leftCalloutAccessoryView设置为不同的图像,您需要查看传递给annotation委托方法的viewForAnnotation参数中的某个值。在最粗略级别,您可以根据annotation.title的值设置图像(例如,如果标题为“A”,则将图像设置为“1”,否则如果标题为“B”然后将图像设置为“2”等。
  2. 点击rightCalloutAccessoryView会因为didSelectAnnotationView中的代码而导致错误的事件ID:

    _eventIndex = [_mapView.annotations indexOfObject:view.annotation];
    

    上面的代码假定地图视图返回的annotations数组与您添加注释的顺序完全相同(并且它只包含你<的注释/ em>已添加,如果showsUserLocationYES,则不是这种情况。这种假设是错误的。不要假设annotations数组在任何特定顺序中 - 不要依赖于它的顺序。

    更好的解决方案是使用您可以使用calloutAccessoryControlTapped直接从view.annotation委托方法访问的注释对象本身。

    由于您需要事件的ID并且默认的MKPointAnnotation类显然没有任何属性可以存储在任何地方,您应该创建自己的类(例如。EventAnnotation)来实现MKAnnotation和为每个注释添加您需要知道的所有事件属性。然后,您将能够使用地图视图的委托方法中的annotation对象直接访问特定于事件的值,而无需尝试引用回原始数组。

    EventAnnotation类可能会这样声明:

    @interface EventAnnotation : NSObject<MKAnnotation>
    @property (assign) CLLocationCoordinate2D coordinate;
    @property (copy) NSString *title;
    @property (copy) NSString *subtitle;
    @property (copy) NSString *eventId;
      //Not sure if your event id is a string.
      //Change to "@property (assign) int eventId;" if it's an integer.
    @end
    

    然后要创建注释,请创建EventAnnotation而不是MKPointAnnotation

    EventAnnotation *aAnnotationPoint = [[EventAnnotation alloc] init];
    CLLocationCoordinate2D theCoordinate;
    theCoordinate.latitude = [_arrEventLatitude[i] doubleValue];
    theCoordinate.longitude = [_arrEventLongitude[i] doubleValue];
    aAnnotationPoint.coordinate = theCoordinate;
    aAnnotationPoint.title = _arrEventNames[i];
    aAnnotationPoint.subtitle = _arrEventDescription[i];
    
    //store event id in the annotation itself...
    aAnnotationPoint.eventId = _arrID[i];
    
    [_mapView addAnnotation:aAnnotationPoint];
    

    最后,在calloutAccessoryControlTapped(您不需要实施didSelectAnnotationView),您可以这样做:

    EventViewerViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"EventViewer"];
    [self.navigationController pushViewController:controller animated:YES];
    
    //cast the view's annotation object to EventAnnotation...
    EventAnnotation *eventAnn = (EventAnnotation *)view.annotation;
    
    NSDictionary *selection = @{@"ID" : eventAnn.eventId,
                                @"eventName" : eventAnn.title };
    
    [controller setValue:selection forKey:@"selection"];
    

  3. 您应该在viewForAnnotation中执行的另一件事是在创建视图后立即显式设置视图的annotation属性。虽然它可能会以某种方式自动分配,但我宁愿明确地做到安全:

    EventAnnotationView *viewAnno = [[EventAnnotationView alloc] initWithFrame:myRect];
    viewAnno.annotation = annotation;  // <-- add this
    



    两个不相关的观点:

    • 我强烈建议您创建一个包含所有这些属性的“Event”类,然后只创建一个Event对象数组,而不是为每个事件属性(Ids,Names,Descriptions,Latitudes等)创建单独的数组。 。实际上,您可以使此Event类实现MKAnnotation本身(而不是创建两个类Event和EventAnnotation)。
    • 代码正在为每个列执行单独的SQL查询。除检索的列外,所有查询都相同。通过在单个SQL查询中获取所有列(例如SELECT ID, Name, Latitude, Longitude, Description FROM Event ORDER BY DateTime DESC),可以大大改善这一点。我对这个DBGMScr课程并不熟悉,但你应该深入研究它。如果该表包含500个注释和5个列,则当前一次只能检索500行时,总共检索2500行。