我有一个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;
}
答案 0 :(得分:2)
这里有几个问题,但首先回答你的两个主要问题:
leftCalloutAccessoryView
设置为不同的图像,您需要查看传递给annotation
委托方法的viewForAnnotation
参数中的某个值。在最粗略级别,您可以根据annotation.title
的值设置图像(例如,如果标题为“A”,则将图像设置为“1”,否则如果标题为“B”然后将图像设置为“2”等。点击rightCalloutAccessoryView
会因为didSelectAnnotationView
中的代码而导致错误的事件ID:
_eventIndex = [_mapView.annotations indexOfObject:view.annotation];
上面的代码假定地图视图返回的annotations
数组与您添加注释的顺序完全相同(并且它只包含你<的注释/ em>已添加,如果showsUserLocation
为YES
,则不是这种情况。这种假设是错误的。不要假设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"];
您应该在viewForAnnotation
中执行的另一件事是在创建视图后立即显式设置视图的annotation
属性。虽然它可能会以某种方式自动分配,但我宁愿明确地做到安全:
EventAnnotationView *viewAnno = [[EventAnnotationView alloc] initWithFrame:myRect];
viewAnno.annotation = annotation; // <-- add this
两个不相关的观点:
SELECT ID, Name, Latitude, Longitude, Description FROM Event ORDER BY DateTime DESC
),可以大大改善这一点。我对这个DBGMScr
课程并不熟悉,但你应该深入研究它。如果该表包含500个注释和5个列,则当前一次只能检索500行时,总共检索2500行。