Try to load a created Map in MKMapView

前端 未结 1 1371
情歌与酒
情歌与酒 2021-01-29 14:10

I am trying to load my Map which I created with a kml File in Google-Maps. The Google Maps Link. I have to say it is only an example, but it is the same principle.

The

相关标签:
1条回答
  • 2021-01-29 14:58

    To load a KML into a MKMapView:

    1. Add the necessary frameworks (MapKit.framework and CoreLocation.framework) to your target;

    2. Load and parse the KML;

    3. Create your annotations on the basis of the KML; and

    4. Set your map's region to encompass the annotations.

    Thus, that might look like:

    #import <MapKit/MapKit.h>
    
    - (void)loadKml:(NSURL *)url
    {
        // parse the kml
    
        Parser *parser = [[Parser alloc] initWithContentsOfURL:url];
        parser.rowElementName = @"Placemark";
        parser.elementNames = @[@"name", @"Snippet", @"coordinates", @"description"];
        parser.attributeNames = nil;
        [parser parse];
    
        // add annotations for each of the entries
    
        for (NSDictionary *locationDetails in parser.items)
        {
            MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
            annotation.title = locationDetails[@"name"];
            annotation.subtitle = locationDetails[@"Snippet"];
            NSArray *coordinates = [locationDetails[@"coordinates"] componentsSeparatedByString:@","];
            annotation.coordinate = CLLocationCoordinate2DMake([coordinates[1] floatValue], [coordinates[0] floatValue]);
            [self.mapView addAnnotation:annotation];
        }
    
        // update the map to focus on the region that encompasses all of your annotations
    
        MKCoordinateRegion region;
        if ([self.mapView.annotations count] > 1)
        {
            region = [self regionForAnnotations:self.mapView.annotations];
            region = MKCoordinateRegionMake(region.center, MKCoordinateSpanMake(region.span.latitudeDelta * 1.05, region.span.longitudeDelta * 1.05));  // expand the region by 5%
        }
        else
        {
            id<MKAnnotation> annotation = self.mapView.annotations[0];
            region = MKCoordinateRegionMakeWithDistance(annotation.coordinate, 100.0, 100.0);
        }
        [self.mapView setRegion:region animated:YES];
    }
    

    My Parser class is just a NSXMLParser subclass that I've written that will create an array of items one per occurrence of rowElementName, and for each row, it will grab the elements listed in the elementNames array.

    Parser.h:

    #import <Foundation/Foundation.h>
    
    @interface Parser : NSXMLParser
    
    @property (nonatomic, strong) NSString *rowElementName; // this is the element name that identifies a new row of data in the XML
    @property (nonatomic, strong) NSArray *attributeNames;  // this is the array of attributes we might want to retrieve for that element name
    @property (nonatomic, strong) NSArray *elementNames;    // this is the list of sub element names for which we're retrieving values
    
    @property (nonatomic, strong) NSMutableArray *items;    // after parsing, this is the array of parsed items
    
    @end
    

    Parser.m:

    #import "Parser.h"
    
    @interface Parser () <NSXMLParserDelegate>
    
    @property (nonatomic, strong) NSMutableDictionary *item;     // while parsing, this is the item currently being parsed
    @property (nonatomic, strong) NSMutableString *elementValue; // this is the element within that item being parsed
    
    @end
    
    @implementation Parser
    
    - (id)initWithContentsOfURL:(NSURL *)url
    {
        self = [super initWithContentsOfURL:url];
    
        if (self)
        {
            self.delegate = self;
        }
    
        return self;
    }
    
    - (id)initWithData:(NSData *)data
    {
        self = [super initWithData:data];
    
        if (self)
        {
            self.delegate = self;
        }
    
        return self;
    }
    
    - (id)initWithStream:(NSInputStream *)stream
    {
        self = [super initWithStream:stream];
    
        if (self)
        {
            self.delegate = self;
        }
    
        return self;
    }
    
    #pragma mark - NSXMLParserDelegate methods
    
    - (void)parserDidStartDocument:(NSXMLParser *)parser
    {
        self.items = [[NSMutableArray alloc] init];
    
        if (!self.rowElementName)
            NSLog(@"%s Warning: Failed to specify row identifier element name", __FUNCTION__);
    }
    
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
    {
        if ([elementName isEqualToString:self.rowElementName])
        {
            self.item  = [[NSMutableDictionary alloc] init];
    
            for (NSString *attributeName in self.attributeNames)
            {
                id attributeValue = [attributeDict valueForKey:attributeName];
                if (attributeValue)
                    [self.item setObject:attributeValue forKey:attributeName];
            }
        }
        else if ([self.elementNames containsObject:elementName])
        {
            self.elementValue = [[NSMutableString alloc] init];
        }
    }
    
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
    {
        if (self.elementValue)
        {
            [self.elementValue appendString:string];
        }
    }
    
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
    {
        if ([elementName isEqualToString:self.rowElementName])
        {
            [self.items addObject:self.item];
            self.item = nil;
        }
        else if ([self.elementNames containsObject:elementName])
        {
            [self.item setValue:self.elementValue forKey:elementName];
            self.elementValue = nil;
        }
    }
    
    @end
    

    Finally, the only other utility method that my loadKml uses is regionForAnnotations, which defines a region based upon a series of annotations. Rob Mooney wrote a simple routine to do that:

    - (MKCoordinateRegion)regionForAnnotations:(NSArray *)annotations {
    
        CLLocationDegrees minLat = 90.0;
        CLLocationDegrees maxLat = -90.0;
        CLLocationDegrees minLon = 180.0;
        CLLocationDegrees maxLon = -180.0;
    
        for (id <MKAnnotation> annotation in annotations) {
            if (annotation.coordinate.latitude < minLat) {
                minLat = annotation.coordinate.latitude;
            }
            if (annotation.coordinate.longitude < minLon) {
                minLon = annotation.coordinate.longitude;
            }
            if (annotation.coordinate.latitude > maxLat) {
                maxLat = annotation.coordinate.latitude;
            }
            if (annotation.coordinate.longitude > maxLon) {
                maxLon = annotation.coordinate.longitude;
            }
        }
    
        MKCoordinateSpan span = MKCoordinateSpanMake(maxLat - minLat, maxLon - minLon);
    
        CLLocationCoordinate2D center = CLLocationCoordinate2DMake((maxLat - span.latitudeDelta / 2), maxLon - span.longitudeDelta / 2);
    
        return MKCoordinateRegionMake(center, span);
    }
    
    0 讨论(0)
提交回复
热议问题