In my app I am using Apple\'s KMLViewer to show annotations that I get from a KML file.In the file KMLParser.m, there is an instance variable, placemarkDescription
It's not clear how much of the KMLViewer sample app code you're using but one way to do this is to create your own annotation class instead of using the MKPointAnnotation
class like the sample app does.
The custom class (eg. "PlacemarkAnnotation
"), should implement the MKAnnotation
protocol or be a sub-class of MKShape
(if you are using the KMLViewer code). In the custom class, add a placemarkDescription
property.
Where the KMLViewer code currently creates an MKPointAnnotation
object, create a PlacemarkAnnotation
instead and set its placemarkDescription
property instead of the subtitle
property.
Then in the viewForAnnotation
delegate method, set the rightCalloutAccessoryView
to a detail disclosure button.
Next, add to the project a detail view controller with a UIWebView
in it. Add a placemarkDescription
property to the view controller. In the viewDidLoad
method, call loadHTMLString
on the web view and pass it placemarkDescription
(I think you can pass nil
for the baseURL
).
In the map view's calloutAccessoryControlTapped
delegate method, create the detail view controller, set its placemarkDescription
property and present it:
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
DetailViewController *dvc = [[DetailViewController alloc] init...
PlacemarkAnnotation *pa = (PlacemarkAnnotation *)view.annotation;
dvc.placemarkDescription = pa.placemarkDescription;
[self presentModalViewController:dvc animated:YES];
[dvc release];
}
Edit:
First, it looks like it will be best to subclass MKShape
for your custom class instead of implementing the MKAnnotation
protocol. The rest of the KMLViewer code is based on this assumption. So change @interface PlacemarkAnnotation2 : NSObject <MKAnnotation>
to @interface PlacemarkAnnotation2 : MKShape
. (By the way, for the NSString
properties, copy
is more appropriate than retain
and it'll get rid of warnings.)
It also looks like you may have changed the type of the mkShape
ivar in KMLPlacemark
(and other places) from MKShape
to something else. Change these types back to MKShape
.
Next, _createShape
might not be the best place to set the placemarkDescription
since that method is called for both overlays and annotations. Remove your changes from that method and put them in the point
method (also in KMLPlacemark
). Note there are a couple of potential memory-related issues with your changes. Here's my suggestion:
- (void)_createShape
{
if (!mkShape) {
mkShape = [[geometry mapkitShape] retain];
mkShape.title = name;
// Skip setting the subtitle for now because they're frequently
// too verbose for viewing on in a callout in most kml files.
}
}
- (id <MKAnnotation>)point
{
[self _createShape];
if ([mkShape isKindOfClass:[PlacemarkAnnotation2 class]])
{
if (placemarkDescription != nil)
//check for nil, otherwise will crash when
//passing to stringByAppendingString below
{
NSString *lessThan = @"<";
NSString *greaterThan = @">";
placemarkDescription = [placemarkDescription stringByReplacingOccurrencesOfString:lessThan
withString:@"<"];
placemarkDescription = [placemarkDescription stringByReplacingOccurrencesOfString:greaterThan
withString:@">"];
NSString *beforeBody = @"<html><body>";
NSString *afterBody = @"</body></html>";
NSString *finalContent = [[beforeBody stringByAppendingString:placemarkDescription]
stringByAppendingString:afterBody];
placemarkDescription = [finalContent retain];
//added retain above since finalContent is autoreleased
//and we are setting the ivar manually. otherwise,
//can result in EXC_BAD_ACCESS later.
}
PlacemarkAnnotation2 *pa2 = (PlacemarkAnnotation2 *)mkShape;
pa2.placemarkDescription = placemarkDescription;
return (id <MKAnnotation>)mkShape;
}
return nil;
}