iPhone: How to draw line between two points on MapKit?

本秂侑毒 提交于 2019-11-26 15:20:23

First make your view controller implement the MKMapViewDelegate protocol and declare the properties you will need:

@property (nonatomic, retain) MKMapView *mapView; //this is your map view
@property (nonatomic, retain) MKPolyline *routeLine; //your line
@property (nonatomic, retain) MKPolylineView *routeLineView; //overlay view

then in viewDidLoad (for example, or wherever you initialize)

//initialize your map view and add it to your view hierarchy - **set its delegate to self***
CLLocationCoordinate2D coordinateArray[2];
coordinateArray[0] = CLLocationCoordinate2DMake(lat1, lon1); 
coordinateArray[1] = CLLocationCoordinate2DMake(lat2, lon2);


self.routeLine = [MKPolyline polylineWithCoordinates:coordinateArray count:2];
[self.mapView setVisibleMapRect:[self.routeLine boundingMapRect]]; //If you want the route to be visible

[self.mapView addOverlay:self.routeLine];

then implement the MKMapViewDelegate's method -(MKOverlayView *)mapView:viewForOverlay:

-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
    if(overlay == self.routeLine)
    {
        if(nil == self.routeLineView)
        {
            self.routeLineView = [[[MKPolylineView alloc] initWithPolyline:self.routeLine] autorelease];
            self.routeLineView.fillColor = [UIColor redColor];
            self.routeLineView.strokeColor = [UIColor redColor];
            self.routeLineView.lineWidth = 5;

        }

        return self.routeLineView;
    }

    return nil;
}

You can adjust the code to fit your need, but it's pretty much straight forward for 2 or more points.

Please See this tutorial to draw polyline or route in mkmapview

1>Draw route using mapkit

2>From versions above ios4.0 You can use MKOverlayPathView See Apple Docs

Sample code :-

create PolyLine:-

    -(void) loadRoute
    {
    NSString* filePath = [[NSBundle mainBundle] pathForResource:@”route” ofType:@”csv”];
    NSString* fileContents = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    NSArray* pointStrings = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

    MKMapPoint northEastPoint;
    MKMapPoint southWestPoint; 

   MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * pointStrings.count);

    for(int idx = 0; idx < pointStrings.count; idx++)
    {
    NSString* currentPointString = [pointStrings objectAtIndex:idx];
    NSArray* latLonArr = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]];

    CLLocationDegrees latitude = [[latLonArr objectAtIndex:0] doubleValue];
    CLLocationDegrees longitude = [[latLonArr objectAtIndex:1] doubleValue];

    CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);

    MKMapPoint point = MKMapPointForCoordinate(coordinate);

        if (idx == 0) {
    northEastPoint = point;
    southWestPoint = point;
    }
    else
    {
    if (point.x > northEastPoint.x)
    northEastPoint.x = point.x;
    if(point.y > northEastPoint.y)
    northEastPoint.y = point.y;
    if (point.x < southWestPoint.x)
    southWestPoint.x = point.x;
    if (point.y < southWestPoint.y)
    southWestPoint.y = point.y;
    }

    pointArr[idx] = point;

    }

        self.routeLine = [MKPolyline polylineWithPoints:pointArr count:pointStrings.count];

    _routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y);

        free(pointArr);

    } 

Display PoluLine :-

[self.mapView addOverlay:self.routeLine]; 

Adding the overlay alone will not render anything on the map. Your MKMapViewDelegate implementation must return an overlay for this route you’ve just added as simply adding won't help .

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay
{
MKOverlayView* overlayView = nil;

if(overlay == self.routeLine)
{
//if we have not yet created an overlay view for this overlay, create it now.
if(nil == self.routeLineView)
{
self.routeLineView = [[[MKPolylineView alloc] initWithPolyline:self.routeLine] autorelease];
self.routeLineView.fillColor = [UIColor redColor];
self.routeLineView.strokeColor = [UIColor redColor];
self.routeLineView.lineWidth = 3;
}

overlayView = self.routeLineView;

}

return overlayView;

} 

#import <MapKit/MapKit.h>   

- (void)viewDidLoad
{
        [mapview setDelegate:self];
        mapview.showsUserLocation = YES; 
}

- (CLLocationCoordinate2D)coordinateWithLocation:(NSDictionary*)location
{
    double latitude = [[location objectForKey:@"lat"] doubleValue];
    double longitude = [[location objectForKey:@"lng"] doubleValue];

    return CLLocationCoordinate2DMake(latitude, longitude);
}

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation   *)userLocation
{

    MKCoordinateSpan span = MKCoordinateSpanMake(0.005, 0.005);
    MKCoordinateRegion region = MKCoordinateRegionMake(userLocation.location.coordinate, span);

    [mapview setRegion:region];

    [mapview setCenterCoordinate:userLocation.coordinate animated:YES];
    NSString *baseUrl = [NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%@&sensor=true", mapview.userLocation.location.coordinate.latitude,  mapview.userLocation.location.coordinate.longitude, @"24.1620661,72.394131"];


    //http://maps.googleapis.com/maps/api/directions/json?origin=23.030000,72.580000&destination=23.400000,72.750000&sensor=true

    NSURL *url = [NSURL URLWithString:[baseUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

    NSLog(@"%@",url);
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

    NSError *error = nil;
    NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];

    NSArray *routes = [result objectForKey:@"routes"];
        NSLog(@"%@",routes);

    NSDictionary *firstRoute = [routes objectAtIndex:0];

    NSDictionary *leg =  [[firstRoute objectForKey:@"legs"] objectAtIndex:0];

    NSDictionary *end_location = [leg objectForKey:@"end_location"];

       NSLog(@"dDDDDDD>>>>>>%@",leg);
    double latitude = [[end_location objectForKey:@"lat"] doubleValue];
    double longitude = [[end_location objectForKey:@"lng"] doubleValue];

    CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);

    MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
    point.coordinate = coordinate;
    point.title =  [leg objectForKey:@"end_address"];
    point.subtitle = @"I'm here!!!";

    [self.mapview addAnnotation:point];

    NSArray *steps = [leg objectForKey:@"steps"];

    int stepIndex = 0;

    CLLocationCoordinate2D stepCoordinates[1  + [steps count] + 1];

    stepCoordinates[stepIndex] = userLocation.coordinate;

    for (NSDictionary *step in steps) {

        NSDictionary *start_location = [step objectForKey:@"start_location"];
        stepCoordinates[++stepIndex] = [self coordinateWithLocation:start_location];

        if ([steps count] == stepIndex){
            NSDictionary *end_location = [step objectForKey:@"end_location"];
            stepCoordinates[++stepIndex] = [self coordinateWithLocation:end_location];
        }
    }

    MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:stepCoordinates count:1 + stepIndex];
    [mapview addOverlay:polyLine];

    CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake((userLocation.location.coordinate.latitude + coordinate.latitude)/2, (userLocation.location.coordinate.longitude + coordinate.longitude)/2);

}];
}

then implement the MKMapViewDelegate's method -(MKOverlayView *)mapView:viewForOverlay:

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
    MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
    polylineView.strokeColor = [UIColor colorWithRed:204/255. green:45/255. blue:70/255. alpha:1.0];
    polylineView.lineWidth = 1;

    return polylineView;
}


- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    static NSString *annotaionIdentifier=@"annotationIdentifier";
    MKPinAnnotationView *aView=(MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:annotaionIdentifier ];
    if (aView==nil) {

        aView=[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:annotaionIdentifier];
        aView.pinColor = MKPinAnnotationColorRed;
        aView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        //        aView.image=[UIImage imageNamed:@"arrow"];
        aView.animatesDrop=TRUE;
        aView.canShowCallout = YES;
        aView.calloutOffset = CGPointMake(-5, 5);
    }

    return aView;
}

First of all Add frame work
    1 Foundation.framework
    2 CoreGraphics.framework
    3 CoreLocation.framework
    4 MapKit.framework

Then create nsobject file Like see.... TrailsMap.h File

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface TrailsMap : NSObject<MKAnnotation>
{
    CLLocationCoordinate2D coordinate;

    NSString *title;
    NSString *image;
    NSString *subtitle;
}

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

- (id)initWithLocation:(CLLocationCoordinate2D)coord;

TrailsMap.m

#import "TrailsMap.h"

@implementation TrailsMap
@synthesize coordinate,title,image,subtitle;

- (id)initWithLocation:(CLLocationCoordinate2D)coord{

    self = [super init];
    if (self) {
        coordinate = coord;

    }
    return self;
}

Now Create coding in mainview Please see..

ViewController.h

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


@interface ViewController : UIViewController<MKMapViewDelegate>

@property (strong, nonatomic) IBOutlet MKMapView *MapView;
@property (nonatomic, retain) MKPolyline *routeLine;
@property (nonatomic, retain) MKPolylineView *routeLineView;

-(void)LoadMapRoute;
@end

Finally create coding in mainview.m file

ViewController.m

#import "ViewController.h"
#import "TrailsMap.h"

@interface ViewController ()
{
    NSData *alldata;
    NSMutableDictionary *data1;

   NSMutableArray *RouteLocation;
   NSMutableArray *RouteName;
}
@end

@implementation ViewController
@synthesize MapView,routeLine,routeLineView;


- (void)viewDidLoad
{
   [super viewDidLoad];

   RouteName = [[NSMutableArray alloc] initWithObjects:@"Ahmedabad",@"Rajkot", nil];
   RouteLocation = [[NSMutableArray alloc] initWithObjects:@"23.0300,72.5800",@"22.3000,70.7833", nil];
   [self LoadMapRoute];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}


//-------------------------------------
// ************* Map ******************
//-------------------------------------

-(void)LoadMapRoute
{
    MKCoordinateSpan span = MKCoordinateSpanMake(0.8, 0.8);
    MKCoordinateRegion region;
    region.span = span;
    region.center= CLLocationCoordinate2DMake(23.0300,72.5800);


    // Distance between two address
   NSArray *coor1=[[RouteLocation objectAtIndex:0] componentsSeparatedByString:@","];
   CLLocation *locA = [[CLLocation alloc] initWithLatitude:[[coor1 objectAtIndex:0] doubleValue] longitude:[[coor1 objectAtIndex:1] doubleValue]];

   NSArray *coor2=[[RouteLocation objectAtIndex:1] componentsSeparatedByString:@","];
   CLLocation *locB = [[CLLocation alloc] initWithLatitude:[[coor2 objectAtIndex:0] doubleValue] longitude:[[coor2 objectAtIndex:1] doubleValue]];
    CLLocationDistance distance = [locA distanceFromLocation:locB];
    NSLog(@"Distance :%.0f Meters",distance);


   NSString *baseUrl = [NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/directions/json?origin=%@&destination=%@&sensor=true", [RouteLocation objectAtIndex:0],[RouteLocation objectAtIndex:1] ];

   NSURL *url = [NSURL URLWithString:[baseUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
   alldata = [[NSData alloc] initWithContentsOfURL:url];

    NSError *err;
    data1 =[NSJSONSerialization JSONObjectWithData:alldata options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves error:&err];

    if (err)
    {
        NSLog(@" %@",[err localizedDescription]);
    }

    NSArray *routes = [data1 objectForKey:@"routes"];
    NSDictionary *firstRoute = [routes objectAtIndex:0];
    NSDictionary *leg =  [[firstRoute objectForKey:@"legs"] objectAtIndex:0];
    NSArray *steps = [leg objectForKey:@"steps"];

    int stepIndex = 0;
    CLLocationCoordinate2D stepCoordinates[[steps count]+1 ];

    for (NSDictionary *step in steps)
    {

        NSDictionary *start_location = [step objectForKey:@"start_location"];
        double latitude = [[start_location objectForKey:@"lat"] doubleValue];
        double longitude = [[start_location objectForKey:@"lng"] doubleValue];
        stepCoordinates[stepIndex] = CLLocationCoordinate2DMake(latitude, longitude);

        if (stepIndex==0)
        {
            TrailsMap *point=[[TrailsMap alloc] initWithLocation:stepCoordinates[stepIndex]];
            point.title =[RouteName objectAtIndex:0];
            point.subtitle=[NSString stringWithFormat:@"Distance :%.0f Meters",distance];
            [self.MapView addAnnotation:point];
        }
        if (stepIndex==[steps count]-1)
        {
            stepIndex++;
            NSDictionary *end_location = [step objectForKey:@"end_location"];
            double latitude = [[end_location objectForKey:@"lat"] doubleValue];
            double longitude = [[end_location objectForKey:@"lng"] doubleValue];
            stepCoordinates[stepIndex] = CLLocationCoordinate2DMake(latitude, longitude);

            TrailsMap *point=[[TrailsMap alloc] initWithLocation:stepCoordinates[stepIndex]];
            point.title = [RouteName objectAtIndex:1];
            point.subtitle=[NSString stringWithFormat:@"Distance :%.0f Meters",distance];

            [self.MapView addAnnotation:point];
        }
        stepIndex++;
    }

    MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:stepCoordinates count: stepIndex];
    [MapView addOverlay:polyLine];
    [MapView setRegion:region animated:YES];
}

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
    MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
    polylineView.strokeColor = [UIColor colorWithRed:204/255. green:45/255. blue:70/255. alpha:1.0];
    polylineView.lineWidth = 5;

    return polylineView;
}

If You want to set multiple pin in map then just add this code. Annotaion is Objectfile.

-(void)LoadMultiplePin
{
    RouteName = [[NSMutableArray alloc] initWithObjects:@"Ahmedabad",@"Rajkot",@"Limdi", nil];
    RouteLocation = [[NSMutableArray alloc] initWithObjects:@"23.0300,72.5800",@"22.3000,70.7833",@"22.5728,71.8114", nil];

    MKCoordinateSpan span = MKCoordinateSpanMake(2.9, 2.9);
    MKCoordinateRegion region;

    region.span = span;
    region.center= CLLocationCoordinate2DMake(22.5728,71.8114);

    int cnt=RouteLocation.count;

    for (int p=0 ; p<cnt ; p++ )
    {
        NSArray *coor=[[RouteLocation objectAtIndex:p] componentsSeparatedByString:@","];

        CLLocationCoordinate2D location=CLLocationCoordinate2DMake([[coor objectAtIndex:0] doubleValue],[[coor objectAtIndex:1] doubleValue]);

        Annotaion *point=[[Annotaion alloc] initWithLocation:location];
        point.title =[RouteName objectAtIndex:p];
        [Map addAnnotation:point];
    }
    [Map setRegion:region animated:YES];

}

By using this code You can easily Drope two pin and draw line between that two Pin Enjoy Happy Coding...:)

I took the great answer from @graver and did this for Swift 3:

// Called from viewDidLoad
func setupMap() {
    mapView.delegate = self
    // BusStop implements the MKAnnotation protocol, I have an array of them
    let routeCoordinates = busStops.map({ $0.coordinate })
    let routeLine = MKPolyline(coordinates: routeCoordinates, count: routeCoordinates.count)
    mapView.setVisibleMapRect(routeLine.boundingMapRect, animated: false)
    mapView.add(routeLine)
}

// MARK: MKMapViewDelegate

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    if let polyline = overlay as? MKPolyline {
        let polylineRenderer = MKPolylineRenderer(overlay: polyline)
        polylineRenderer.strokeColor = .blue
        polylineRenderer.lineWidth = 3
        return polylineRenderer
    }
    return MKOverlayRenderer(overlay: overlay)
}
Avinash Meghanathi

pass your address cordination

-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) f to: (CLLocationCoordinate2D) t {
    NSString* saddr = [NSString stringWithFormat:@"%f,%f", f.latitude, f.longitude];
    NSString* daddr = [NSString stringWithFormat:@"%f,%f", t.latitude, t.longitude];

NSString* apiUrlStr = [NSString stringWithFormat:@"http://maps.google.com/maps?             output=dragdir&saddr=%@&daddr=%@", saddr, daddr];
//    NSString* apiUrlStr = @"http://maps.google.com/maps?output=dragdir&saddr=40.769264,-73.958995&daddr=47.286522,-122.312932";
NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
NSLog(@"api url: %@", apiUrl);
NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl encoding:NSUTF8StringEncoding error:nil];
NSString* encodedPoints = [apiResponse stringByMatching:@"points:\\\"([^\\\"]*)\\\"" capture:1L];
return [self decodePolyLine:[encodedPoints mutableCopy]];
}


-(NSMutableArray *)decodePolyLine: (NSMutableString *)encoded {
    [encoded replaceOccurrencesOfString:@"\\\\" withString:@"\\"
                                options:NSLiteralSearch
                                  range:NSMakeRange(0, [encoded length])];
    NSInteger len = [encoded length];
    NSInteger index = 0;
    NSMutableArray *array = [[NSMutableArray alloc] init];
    NSInteger lat=0;
    NSInteger lng=0;
    while (index < len) {
        NSInteger b;
        NSInteger shift = 0;
        NSInteger result = 0;
        do {
            b = [encoded characterAtIndex:index++] - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
        lat += dlat;
        shift = 0;
        result = 0;
        do {
            b = [encoded characterAtIndex:index++] - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
        lng += dlng;
        NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
        NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
        printf("[%f,", [latitude doubleValue]);
        printf("%f]", [longitude doubleValue]);
        CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
        [array addObject:loc];
    }

    return array;
}

-(void) updateRouteView:(UIColor *)clr {
    CGContextRef context =CGBitmapContextCreate(nil,routeView.frame.size.width,routeView.frame.size.height,8,4 * routeView.frame.size.width,CGColorSpaceCreateDeviceRGB(), kCGImageAlphaPremultipliedLast);

    CGContextSetStrokeColorWithColor(context, clr.CGColor);
    CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
    CGContextSetLineWidth(context, 3.0);

    for(int i = 0; i < routes.count; i++) {
        CLLocation* location = [routes objectAtIndex:i];
        CGPoint point = [mapView convertCoordinate:location.coordinate toPointToView:routeView];

        if(i == 0) {
            CGContextMoveToPoint(context, point.x, routeView.frame.size.height - point.y);
        } else {
            CGContextAddLineToPoint(context, point.x, routeView.frame.size.height - point.y);

        }
    }

    CGContextStrokePath(context);

    CGImageRef image = CGBitmapContextCreateImage(context);
    UIImage* img = [UIImage imageWithCGImage:image];

    routeView.image = img;
    CGContextRelease(context);

}

You can draw lines in map using MKPolyline.

See this link

http://spitzkoff.com/craig/?p=136

ALSO:

https://github.com/kishikawakatsumi/MapKit-Route-Directions

http://cloudmade.com/

These are all tutorials and open source libraries which you can easily refer to. Currently MapKit does not support this feature...

here you must calculate the route with its latitude and longtitude and then draw the poly line on MapView........ I do this things in my app....i draw route on mapview with all information....

here if you MapKit and also use RagexKitLite then its too simple for you just get Demo of RagexKitLite....

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!