Last active
December 18, 2017 08:49
-
-
Save lamprosg/5046828 to your computer and use it in GitHub Desktop.
(iOS) Core Location & Map Kit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/**************************************/ | |
//Annotation object | |
#import <Foundation/Foundation.h> | |
#import <MapKit/MapKit.h> | |
@interface MapViewAnnotation : NSObject <MKAnnotation> | |
@property (nonatomic,strong) NSString *title; | |
@property (nonatomic,strong) NSString *subtitle; | |
@property (nonatomic, assign) CLLocationCoordinate2D coordinate; | |
-(id) initWithTitle:(NSString *)title subTitle:(NSString*)subtitle AndCoordinate:(CLLocationCoordinate2D)coordinate; | |
@end | |
//------- | |
#import “MapViewAnnotation.h” | |
@implementation MapViewAnnotation | |
-(id) initWithTitle:(NSString *)title subTitle:(NSString*)subtitle AndCoordinate:(CLLocationCoordinate2D)coordinate | |
{ | |
self = [super init]; | |
self.title = title; | |
self.subtitle = subtitle; | |
self.coordinate = coordinate; | |
return self; | |
} | |
@end | |
/**************************************/ | |
//HEADER FILE | |
#import <UIKit/UIKit.h> | |
#import <MapKit/MapKit.h> | |
@interface MapView : MKMapView <MKMapViewDelegate> | |
@property (nonatomic,strong) NSArray *locations; | |
@property (nonatomic,strong) NSMutableArray *annotations; | |
-(void)showMap; | |
@end | |
//---------------------------- | |
//IMPLEMENTATION FILE | |
@implementation MapView { | |
CLLocationDegrees centerLatitude; | |
CLLocationDegrees centerLongitude; | |
double span; | |
} | |
-(NSMutableArray*) createAnnotations | |
{ | |
annotations = [[NSMutableArray alloc] init]; | |
for (NSDictionary *row in locations) { | |
NSNumber *latitude = [row objectForKey:@”latitude”]; | |
NSNumber *longitude = [row objectForKey:@”longitude”]; | |
NSString *title = [row objectForKey:@”title”]; | |
NSString *subTitle = [row objectForKey:@”subTitle”]; | |
//Create coordinates from the latitude and longitude values | |
CLLocationCoordinate2D coord; | |
coord.latitude = latitude.doubleValue; | |
coord.longitude = longitude.doubleValue; | |
MapViewAnnotation *annotation = [[MapViewAnnotation alloc] initWithTitle:title subTitle:subtitle AndCoordinate:coord]; | |
[annotations addObject:annotation]; | |
} | |
return annotations; | |
} | |
-(void) zoomToFit { | |
if (!locations || ![locations count]) { | |
centerLatitude = centerLongitude = 0.0; | |
span = 180; | |
return; | |
} | |
// compute center & span based on the min/max of all pin locations & polyline points | |
// minimum span is 0.04 | |
double minLat = 1000.0; | |
double minLng = 1000.0; | |
double maxLat = -1000.0; | |
double maxLng = -1000.0; | |
for (NSDictionary *dict in locations) { | |
NSNumber *latitude = [row objectForKey:@”latitude”]; | |
NSNumber *longitude = [row objectForKey:@”longitude”]; | |
NSString *title = [row objectForKey:@”title”]; | |
minLat = MIN(minLat, [latitude doubleValue]); | |
minLng = MIN(minLng, [longitude doubleValue]); | |
maxLat = MAX(maxLat, [latitude doubleValue]); | |
maxLng = MAX(maxLng, [longitude doubleValue]); | |
} | |
centerLatitude = minLat + (maxLat - minLat)/2.0; | |
centerLongitude = minLng + (maxLng - minLng)/2.0; | |
double maxDelta = MAX(maxLat - minLat, maxLng - minLng); | |
span = MIN(MAX(maxDelta*1.05, 0.02), 180); | |
} | |
-(void)showMap { | |
//Remove old annotations except for user's location | |
NSMutableArray *oldAnnotations = [NSMutableArray arrayWithArray:annotations]; | |
for (int i=0; i<[oldAnnotations count]; ++i) { | |
if ([[oldAnnotations objectAtIndex:i] class] == MKUserLocation.class) { | |
[oldAnnotations removeObjectAtIndex:i]; | |
break; | |
} | |
} | |
[self removeAnnotations:oldAnnotations]; | |
//Add fresh annotations | |
[self addAnnotations:[self createAnnotations]]; | |
[self zoomToFit]; | |
//Set the center location and span | |
MKCoordinateSpan span; | |
span.latitudeDelta = span; | |
span.longitudeDelta = span; | |
MKCoordinateRegion region; | |
CLLocationCoordinate2D center; | |
center.latitude = centerLatitude; | |
center.longitude = centerLongitude; | |
self.region.center = center; | |
self.region.span = span; | |
self.region = region; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Model class | |
//Here we'll represent data (coordinates, titles etc.) on the map | |
#import <Foundation/Foundation.h> | |
#import <MapKit/MapKit.h> | |
@interface BIDPlace : NSObject <MKAnnotation> | |
//Location, title and subtitle of the marker | |
@property (copy, nonatomic) NSString *title; | |
@property (copy, nonatomic) NSString *subtitle; | |
@property (assign, nonatomic) CLLocationCoordinate2D coordinate; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <UIKit/UIKit.h> | |
//You need to add location kit and map kit to your project | |
//For the Location framework | |
#import <CoreLocation/CoreLocation.h> | |
//Import our model class for the map | |
#import "BIDPlace.h" | |
//Added CLLocationManager delegate and MKMapViewDelegate | |
@interface BIDViewController : UIViewController <CLLocationManagerDelegate> <MKMapViewDelegate> | |
//Will hold the instance of the Core Location we'll create | |
@property (strong, nonatomic) CLLocationManager *locationManager; | |
//We will set this to the location we receive in the first update from the location manager | |
//This way, if the user has our program running and moves far enough to trigger updates, | |
//we’ll be able to calculate how far our user moved | |
@property (strong, nonatomic) CLLocation *startPoint; | |
@property (assign, nonatomic) CLLocationDistance distanceFromStart; | |
//Outlets | |
@property (weak, nonatomic) IBOutlet UILabel *latitudeLabel; | |
@property (weak, nonatomic) IBOutlet UILabel *longitudeLabel; | |
@property (weak, nonatomic) IBOutlet UILabel *horizontalAccuracyLabel; | |
@property (weak, nonatomic) IBOutlet UILabel *altitudeLabel; | |
@property (weak, nonatomic) IBOutlet UILabel *verticalAccuracyLabel; | |
@property (weak, nonatomic) IBOutlet UILabel *distanceTraveledLabel; | |
//Outelet to a map view | |
@property (weak, nonatomic) IBOutlet MKMapView *mapView; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@implementation BIDViewController | |
//Initialization | |
- (void)viewDidLoad | |
{ | |
[super viewDidLoad]; | |
// Do any additional setup after loading the view, typically from a nib. | |
if (![CLLocationManager locationServicesEnabled]) | |
{ | |
//Locations are disabled | |
return; | |
} | |
//Allocate the CLLocationManager | |
self.locationManager = [[CLLocationManager alloc] init]; | |
if ([_locationManager locationServicesEnabled]) | |
{ | |
//Set this controller class as the delegate | |
_locationManager.delegate = self; | |
//Set the desired accuracy to the best available | |
_locationManager.desiredAccuracy = kCLLocationAccuracyBest; | |
/* Notify changes when device has moved x meters. | |
* Default value is kCLDistanceFilterNone: all movements are reported. | |
*/ | |
_locationManager.distanceFilter = 10.0f; //Optional | |
/* Notify heading changes when heading is > 5. | |
* Default value is kCLHeadingFilterNone: all movements are reported. | |
*/ | |
_locationManager.headingFilter = 5; //Optional | |
//Start giving us location updates | |
[_locationManager startUpdatingLocation]; | |
//In order to run in the background you have to set at the info.plist | |
//a new line with the key "UIBackgroundModes" | |
//with the value "location" | |
//See: | |
https://gist.github.com/lamprosg/5345446 | |
/**************************************/ | |
//OR | |
[_locationManager startMonitoringSignificantLocationChanges]; | |
//This initiates the delivery of location events asynchronously | |
//only when a significant change in the user’s location is detected (ex. different cell tower, every 500m every 5 min) | |
//does not rely on the value in the distanceFilter property to generate events | |
//CAN RUN IN THE BACKGROUND (must be set in the info.plist) | |
//Add to info.plist a new line with the key "Required Background Modes" | |
//Then select the "App registers for location updates", and you're done | |
http://mobile.tutsplus.com/tutorials/iphone/ios-multitasking-background-location/ | |
//To stop it: | |
[_locationManager stopMonitoringSignificantLocationChanges]; | |
/**************************************/ | |
} | |
/************************************** | |
Since this class designated itself as the location manager’s delegate, | |
location updates will come into the | |
LocationManager:didUpdateLocations: | |
**************************************/ | |
//Show the user's location on the map | |
_mapView.showsUserLocation = YES; | |
//Set map zool level if you want to | |
//Set map zoom level | |
MKCoordinateRegion region; | |
region.center=Eng.locationTracker.currentlocation.coordinate; // Current location | |
MKCoordinateSpan span; | |
span.latitudeDelta = 0.007; // From 0.001 to 120 | |
span.longitudeDelta = 0.007; | |
region.span=span; | |
[_mapView setRegion:region animated:YES]; | |
} | |
- (void)didReceiveMemoryWarning | |
{ | |
[super didReceiveMemoryWarning]; | |
// Dispose of any resources that can be recreated. | |
} | |
#pragma mark - | |
#pragma mark CLLocationManagerDelegate Methods | |
- (void)locationManager:(CLLocationManager *)manager | |
didUpdateLocations:(NSArray *)locations | |
{ | |
//The updated location | |
CLLocation *newLocation = [locations lastObject]; | |
//Update coordinates | |
NSString *latitudeString = [NSString stringWithFormat:@"%g\u00B0", newLocation.coordinate.latitude]; | |
_latitudeLabel.text = latitudeString; | |
NSString *longitudeString = [NSString stringWithFormat:@"%g\u00B0", newLocation.coordinate.longitude]; | |
_longitudeLabel.text = longitudeString; | |
NSString *horizontalAccuracyString = [NSString stringWithFormat:@"%gm", newLocation.horizontalAccuracy]; | |
_horizontalAccuracyLabel.text = horizontalAccuracyString; | |
NSString *altitudeString = [NSString stringWithFormat:@"%gm", newLocation.altitude]; | |
_altitudeLabel.text = altitudeString; | |
NSString *verticalAccuracyString = [NSString stringWithFormat:@"%gm", newLocation.verticalAccuracy]; | |
_verticalAccuracyLabel.text = verticalAccuracyString; | |
//Negative accuracy means the location is invalid | |
if (newLocation.verticalAccuracy < 0 || newLocation.horizontalAccuracy < 0) | |
{ | |
// invalid accuracy | |
return; | |
} | |
//High accuracy means it doesn't know where we are | |
if (newLocation.horizontalAccuracy > 100 || newLocation.verticalAccuracy > 50) { | |
// accuracy radius is so large, we don't want to use it | |
return; | |
} | |
if (_startPoint == nil) //If it's the first update, set it as a starting point | |
{ | |
self.startPoint = newLocation; | |
self.distanceFromStart = 0; | |
//Deal with the map | |
//Create a BIDPlace instance | |
BIDPlace *start = [[BIDPlace alloc] init]; | |
//Set the starting coordinate | |
start.coordinate = newLocation.coordinate; | |
//Set the title and the subtitle of the pin | |
start.title = @"Start Point"; | |
start.subtitle = @"This is where we started!"; | |
//Pass the object to the map view | |
[_mapView addAnnotation:start]; | |
/*************************************** | |
You can put more markers on the map this way | |
by setting new instances of VIDPlace in our case | |
and then | |
[_mapview addAnnptation:instance]; | |
****************************************/ | |
//MKCoordinateRegion let's us tell the view which section of the map we want to display | |
//Using our location coordinates and a pair of distance in meters (wide and tall) | |
MKCoordinateRegion region; | |
region = MKCoordinateRegionMakeWithDistance(newLocation.coordinate,100,100); | |
//Pass the region to the map view | |
[_mapView setRegion:region animated:YES]; | |
} | |
else //Else calculate the distance from the starting point | |
{ | |
self.distanceFromStart = [newLocation distanceFromLocation:_startPoint]; | |
} | |
//Update the distance label | |
NSString *distanceString = [NSString stringWithFormat:@"%gm", _distanceFromStart]; | |
_distanceTraveledLabel.text = distanceString; | |
} | |
//Error updating | |
- (void)locationManager:(CLLocationManager *)manager | |
didFailWithError:(NSError *)error | |
{ | |
//Get the error and display it as an alert | |
NSString *errorType = (error.code == kCLErrorDenied) ? | |
@"Access Denied" : @"Unknown Error"; | |
UIAlertView *alert = [[UIAlertView alloc] | |
initWithTitle:@"Error getting Location" | |
message:errorType | |
delegate:nil | |
cancelButtonTitle:@"Okay" | |
otherButtonTitles:nil]; | |
[alert show]; | |
} | |
#pragma mark MKMapViewDelegate Methods | |
//Whenever you call addAnnotation method, the below method is fired | |
//You have to set the mapview delegate to self first | |
//ex. | |
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { | |
// in case it's the user location, we already have an annotation, so just return nil | |
if ([annotation isKindOfClass:[MKUserLocation class]]) | |
return nil; | |
NSLog(@"ViewForAnnotationCalled"); | |
// try to dequeue an existing pin view first | |
static NSString *annotationIdentifier = @"annotationIdentifier"; | |
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier]; | |
if (pinView == nil) | |
{ | |
// if an existing pin view was not available, create one | |
MKPinAnnotationView *customPinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier]; | |
customPinView.animatesDrop = YES; | |
customPinView.canShowCallout = YES; | |
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; | |
[rightButton addTarget:self | |
action:@selector(showDetails:) | |
forControlEvents:UIControlEventTouchUpInside]; | |
customPinView.rightCalloutAccessoryView = rightButton; | |
//Green pins for sell and red for buy | |
if ([((Record *)[Eng.search.resultsHome objectAtIndex:[(MapAnnotation *)annotation tag]]) type].isSell) | |
{ | |
customPinView.pinColor = MKPinAnnotationColorGreen; | |
} | |
else | |
{ | |
customPinView.pinColor = MKPinAnnotationColorRed; | |
} | |
customPinView.rightCalloutAccessoryView.tag = [(MapAnnotation *)annotation tag]; | |
return [customPinView autorelease]; | |
} | |
else | |
{ | |
pinView.annotation = annotation; | |
//Green pins for sell and red for buy | |
if ([((Record *)[Eng.search.resultsHome objectAtIndex:[(MapAnnotation *)annotation tag]]) type].isSell) | |
{ | |
pinView.pinColor = MKPinAnnotationColorGreen; | |
} | |
else | |
{ | |
pinView.pinColor = MKPinAnnotationColorRed; | |
} | |
pinView.rightCalloutAccessoryView.tag = [(MapAnnotation *)annotation tag]; | |
} | |
return pinView; | |
} | |
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState | |
{ | |
//..Whatever you want to happen when the dragging starts or stops | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CLLocationCoordinate2D coords = CLLocationCoordinate2DMake(40.74835, -73.984911); | |
NSDictionary *address = @{ | |
(NSString *)kABPersonAddressStreetKey: @"350 5th Avenue", | |
(NSString *)kABPersonAddressCityKey: @"New York", | |
(NSString *)kABPersonAddressStateKey: @"NY", | |
(NSString *)kABPersonAddressZIPKey: @"10118", | |
(NSString *)kABPersonAddressCountryCodeKey: @"US" | |
}; | |
MKPlacemark *place = [[MKPlacemark alloc] initWithCoordinate:coords addressDictionary:address]; | |
//OR | |
MKMapItem *mapItem = [[MKMapItem alloc]initWithPlacemark:myplacemark]; | |
/************************************************************************/ | |
//OR | |
double latitude = 35.0; | |
double longitude = 1.0; | |
MKPlacemark *placemark = [[[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) addressDictionary:nil] autorelease]; | |
MKMapItem *mapItem = [[[MKMapItem alloc] initWithPlacemark:placemark] autorelease]; | |
[mapItem setName:@"Name of your location"]; | |
[mapItem openInMapsWithLaunchOptions:nil]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CLGeocoder *geocoder = [[CLGeocoder alloc] init]; | |
[geocoder geocodeAddressString:@"350 5th Avenue New York, NY" | |
completionHandler:^(NSArray *placemarks, NSError *error) { | |
if (error) { | |
NSLog(@"Geocode failed with error: %@", error); | |
return; | |
} | |
if(placemarks && placemarks.count > 0) | |
{ | |
//For example take the 1st placemark | |
CLPlacemark *placemark = placemarks[0]; | |
CLLocation *location = placemark.location; | |
CLLocationCoordinate2D coords = location.coordinate; | |
NSLog(@"Latitude = %f, Longitude = %f", | |
coords.latitude, coords.longitude); | |
} | |
} | |
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CLGeocoder *geocoder = [[CLGeocoder alloc] init]; | |
CLLocation *newLocation = [[CLLocation alloc]initWithLatitude:40.74835 | |
longitude:-73.984911]; | |
[geocoder reverseGeocodeLocation:newLocation | |
completionHandler:^(NSArray *placemarks, NSError *error) { | |
if (error) { | |
NSLog(@"Geocode failed with error: %@", error); | |
return; | |
} | |
if (placemarks && placemarks.count > 0) | |
{ | |
CLPlacemark *placemark = placemarks[0]; | |
NSDictionary *addressDictionary = | |
placemark.addressDictionary; | |
NSString *address = [addressDictionary | |
objectForKey:(NSString *)kABPersonAddressStreetKey]; | |
NSString *city = [addressDictionary | |
objectForKey:(NSString *)kABPersonAddressCityKey]; | |
NSString *state = [addressDictionary | |
objectForKey:(NSString *)kABPersonAddressStateKey]; | |
NSString *zip = [addressDictionary | |
objectForKey:(NSString *)kABPersonAddressZIPKey]; | |
NSLog(@"%@ %@ %@ %@", address,city, state, zip); | |
} | |
}]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CLLocationManager *locationManager = [[CLLocationManager alloc] init]; | |
locationManager.delegate=self; | |
locationManager.desiredAccuracy=kCLLocationAccuracyBestForNavigation; | |
// Start heading updates. | |
if (locationManager.headingAvailable && locationManager.locationServicesEnabled) | |
{ | |
locationManager.headingFilter = kCLHeadingFilterNone; | |
[locationManager startUpdatingLocation]; //Sometimes you need that in order to work | |
[locationManager startUpdatingHeading]; | |
} | |
//Delegate method | |
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading { | |
// Use the true heading if it is valid. | |
[lblAccuracy setText:[NSString stringWithFormat:@"%.1fmi",newHeading.headingAccuracy]]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Create a new location manager | |
locationManager = [[CLLocationManager alloc] init]; | |
// Set the location manager delegate | |
[locationManager setDelegate:self]; | |
// Create a new CLRegion based on the lat/long | |
// position of Apple's main campus | |
CLLocationCoordinate2D appleLatLong = | |
CLLocationCoordinate2DMake(37.331691, -122.030751); | |
CLRegion *appleCampus = [[CLRegion alloc] | |
initCircularRegionWithCenter:appleLatLong | |
radius:100 | |
identifier:@"Apple"]; | |
// Start monitoring for our CLRegion using best accuracy | |
[locationManager startMonitoringForRegion:appleCampus | |
desiredAccuracy:kCLLocationAccuracyBest]; | |
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region | |
{ | |
//What happens when you enter the specific region | |
} | |
- (void)locationManager:(CLLocationManager *)managerdidExitRegion:(CLRegion *)region | |
{ | |
//What happens when you exit the specific region | |
} | |
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error | |
{ | |
//Region monitoring error occured | |
NSLog(@"Region monitoring failed with error: %@", [error localizedDescription]); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Needs to comfort <MKOverlay> protocol | |
MKPolyline* polyline = [[MKPolyline alloc] init]; | |
CLLocationCoordinate2D coord[2]; | |
coord[0] = myPreviousLocation; | |
coord[1] = myCurrentLocation; | |
polyline = [MKPolyline polylineWithCoordinates:coord count:2]; | |
[self.mapView addOverlay:polyline]; | |
myPreviousLocation = Eng.locationTracker.currentlocation.coordinate; | |
..... | |
//Overlay delegate | |
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay { | |
MKPolylineView *polyLineView = [[MKPolylineView alloc] initWithPolyline:polyline]; | |
polyLineView.fillColor = [UIColor blueColor]; | |
polyLineView.strokeColor = [UIColor blueColor]; | |
polyLineView.lineWidth = 5; | |
return polyLineView; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
MKPinkAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:[annotation title]];
pin.animatesDrop = YES;
pin.canShowCallout = YES;
pin.draggable = YES;