2015年8月4日 星期二

iOS筆記:Core Location & MapKit(2)

How To Get the User Location

Adding Core Location Framework

我們必須手動自己添加 Core Location Framework
enter image description here

Back to the code, and to let the view controller know about the CLLocationManagerDelegate, you first import the corresponding header file. In the “ViewController.h”, add the #import statement and implement the “CLLocationManagerDelegate”.

#import <CoreLocation/CoreLocation.h>

@interface ViewController : UIViewController <CLLocationManagerDelegate>

@property (strong, nonatomic) IBOutlet UILabel *latitudeLabel;
@property (strong, nonatomic) IBOutlet UILabel *longtitudeLabel;
@property (strong, nonatomic) IBOutlet UILabel *addressLabel;
- (IBAction)getCurrentLocetion:(id)sender;

@end

Now go to the “MyLocationViewController.m”. The CLLocationManager is the object that provides you the location data.

@implementation ViewController
{
    CLLocationManager *locationManager;
}

Once you initialize a CLLocationManager object, you can simply call the startUpdatingLocation method to the location service. The service will then continuously send your application a stream of location data.

- (void)viewDidLoad {
    [super viewDidLoad];

    locationManager = [[CLLocationManager alloc] init];
}

The location data is reported to your app via the location manager’s associated delegate object. All the location updates will send to the delegate. To capture the location event, we have to implement the delegate methods as defined in the protocol.

- (IBAction)getCurrentLocetion:(id)sender {

    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    [locationManager requestWhenInUseAuthorization]; 
    #使用程式期間允許獲取位置的數據 (iOS8需要)
    [locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"didFailWithError: %@", error);
    UIAlertView *errorAlert = 
    [[UIAlertView alloc] initWithTitle:@"Error" message:@"Failed to Get Your Location" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [errorAlert show];
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    #第0個位置資訊,表示為最新的位置資訊
    CLLocation * currentLocation = [locations objectAtIndex:0];
    _longtitudeLabel.text = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];

    _latitudeLabel.text = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
}

如果是在iOS8的版本實作的話請記得在Info.plist文件中添加如下配置.
(1)NSLocationAlwaysUsageDescription
(2)NSLocationWhenInUseUsageDescription
enter image description here

Test.
選Location\City Run,表示會以走路的方式模擬手機所在位置,如此就可取得位置變動的資訊,接著即可看到經緯度隨時間一再的變更.
enter image description here

enter image description here

Finding the Address

The CLGeocoder class provides services for converting between a GPS coordinate and the user-readable address of that coordinate. By specify the latitude and longitude of a given location, you can use CLGeocoder to find a user-readable address.
新增 instance variables: geocoder and placemark.

@implementation MyLocationViewController {
    CLLocationManager *locationManager;
    CLGeocoder *geocoder;
    CLPlacemark *placemark;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    locationManager = [[CLLocationManager alloc] init];
    geocoder = [[CLGeocoder alloc] init];
}

Update the “didUpdateToLocation” method to include the code for reverse geocoding:

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations

# Reverse Geocoding
    NSLog(@"Resolving the Address");
    [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
        NSLog(@"Found placemarks: %@, error: %@", placemarks, error);
        if (error == nil && [placemarks count] > 0) {
            placemark = [placemarks lastObject];
            addressLabel.text = [NSString stringWithFormat:@"%@ %@\n%@ %@\n%@\n%@",                                                                    placemark.subThoroughfare, placemark.thoroughfare,
placemark.postalCode, placemark.locality, placemark.administrativeArea, placemark.country];
        } else {
            NSLog(@"%@", error.debugDescription);
        }
    } ];

Saving Battery Power

一直開啟GPS是一件非常耗電的事情, 因為他會一直update現在的位置, 即使你位置沒有變動.
Use the “stopUpdatingLocation” method to disable the location update.

[locationManager stopUpdatingLocation];

MapKit API and Add an Annotation on Map

enter image description here

Make sure add both “CoreLocation” and “MapKit” frameworks.
enter image description here

Zoom Into the Current Location

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

@interface MyLocationViewController : UIViewController <MKMapViewDelegate>

@property (nonatomic, strong) IBOutlet MKMapView *mapView;

@end

The MKMapViewDelegate protocol defines a set of optional methods that you can use to receive map-related update messages. The mapView:didUpdateUserLocation method is called whenever a new location update is received by the map view.

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.mapView.delegate = self;
}

Annotation: mapkit提供的是一個藍色的原點來代表位置, 透過下面的方式可以得到一個pin來顯在自己的位置, 這麼pin的顏色可以更換或是自訂圖案, 再點選之後也可以出現照片等等…

To place a pin in the correct location on map, we first create a MKPointAnnotation object and assign it with the coordinate of user’s location. We also assign the title and subtitle for the call-out that appears when you tap on the pin. Lastly, we call the addAnnotation: method to add the annotation object to the map view.

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
    [self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
}
    # Add an annotation
    MKPointAnnotation *point1 = [[MKPointAnnotation alloc] init];
    point1.coordinate = CLLocationCoordinate2DMake(25.0335, 121.5651);
    point1.title = @"Taipei";
    point1.subtitle = @"ROC";
    [self.mapview addAnnotation:point1];
#建立MapPin時會呼叫的函式
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {

    #判斷Pin如果是目前位置就不修改
    if ([annotation isKindOfClass:[MKUserLocation class]]) {
        return nil;
    }

    MKPinAnnotationView *pinView = [[MKPinAnnotationView alloc]
                                    initWithAnnotation:annotation reuseIdentifier:@"PinView"];

    #設定顏色
    pinView.pinColor = MKPinAnnotationColorGreen;

    UIImage *image = [UIImage imageNamed:@"tomorrowland.jpg"];
    UIImageView  *imageView = [[UIImageView alloc] initWithImage:image];

    #重設圖片大小與座標
    imageView.frame = CGRectMake(0, 0, 46, 46);

    #設定註解內的圖片
    pinView.leftCalloutAccessoryView = imageView;

    #點擊時是否出現註解
    pinView.canShowCallout = YES;

    return pinView;
}

參考:
http://www.bkjia.com/IOSjc/987975.html
http://lokanghung.blogspot.tw/2014/05/ios-cllocationmanager.html
http://www.appcoda.com/how-to-get-current-location-iphone-user/
http://www.appcoda.com/ios-programming-101-drop-a-pin-on-map-with-mapkit-api/
http://furnacedigital.blogspot.tw/2011/01/map-view-pin.html

沒有留言:

張貼留言