定位與地圖
Location
Get Location 檢查定位方式是否打開 建立一個CLLocationManager物件並設定 delegate用來 接收位置改變資訊 設定需要的位置更新類型 啟動偵測位置改變
CLLocationManager 需加入CoreLocation framework 檢查位置服務是否開啟 檢查是否可取得裝置朝向資訊 + (BOOL)locationServicesEnabled 檢查是否可取得裝置朝向資訊 + (BOOL)headingAvailable (compass)
CLLocationManager + (CLAuthorizationStatus)authorizationStatus 應用程式授權位置服務狀態 typedef enum { kCLAuthorizationStatusNotDetermined = 0, kCLAuthorizationStatusRestricted , kCLAuthorizationStatusDenied , kCLAuthorizationStatusAuthorized , kCLAuthorizationStatusAuthorizedAlways = kCLAuthorizationStatusAuthorized , kCLAuthorizationStatusAuthorizedWhenInUse } CLAuthorizationStatus;
CLLocationManager Property CLLocationAccuracy desiredAccuracy 設定要求位置之精確度,預設kCLLocationAccuracyBest kCLLocationAccuracyBestForNavigation; kCLLocationAccuracyBest; kCLLocationAccuracyNearestTenMeters; kCLLocationAccuracyHundredMeters; kCLLocationAccuracyKilometer; kCLLocationAccuracyThreeKilometers; phone should be plugged in to power source The more accuracy you request, the more battery will be used
CLLocationManager Property CLLocationDistance distanceFilter 預設是kCLDistanceFilterNone 只要移動就會有更新事件發 生 CLLocation *location 最近取得的位置 CLHeading *heading 最近取得的裝置方位朝向 id<CLLocationManagerDelegate> delegate 設定位置更新事件的 delegate物件 You can just ask the CLLocationManager for the location or heading, but usually we don’t. We let it update us when the location changes (enough) via its delegate.
CLLocationManager Property CLLocationDegrees headingFilter 設定角度更新事件的度數 (measured in degrees) 預設是kCLHeadingFilterNone 只要有更動就會發生事件 CLDeviceOrientation headingOrientation 角度的參考點,預設是手機的頂端代表北方(0度) typedef enum { CLDeviceOrientationUnknown = 0, CLDeviceOrientationPortrait, CLDeviceOrientationPortraitUpsideDown, CLDeviceOrientationLandscapeLeft, CLDeviceOrientationLandscapeRight, CLDeviceOrientationFaceUp, CLDeviceOrientationFaceDown } CLDeviceOrientation;
CLLocationManager -(void)startUpdatingLocation - (void)stopUpdatingLocation 啟動/停止位置更新事件 - (void)startUpdatingHeading - (void)stopUpdatingHeading 啟動/停止方向更新事件 - (void)dismissHeadingCalibrationDisplay 方位校正視窗關閉
CLLocationManagerDelegate Protocol - (void)locationManager:(CLLocationManager *) manager didUpdateLocations:(NSArray *)locations 有新位置資訊產生 locations: An array of CLLocation objects,最近取得的位置在陣列最後面 - (void)locationManager:(CLLocationManager *) manager didFailWithError:(NSError *)error 無法取得位置資訊 error kCLErrorLocationUnknown: location service is unable to retrieve a location fix right away, keeps trying. kCLErrorDenied: user denies application’s use of the location service kCLErrorHeadingFailure: too much local magnetic interference, keep waiting
CLLocationManagerDelegate Protocol - (void)locationManagerDidPauseLocationUpdates: (CLLocationManager *)manager - (void)locationManagerDidResumeLocationUpdates: (CLLocationManager *)manager - (void)locationManager:(CLLocationManager *) manager didChangeAuthorizationStatus: (CLAuthorizationStatus) status
CLLocationManagerDelegate - (BOOL) locationManagerShouldDisplayHeadingCalibration: (CLLocationManager *) manager 是否要顯示校正視窗 校正完後視窗會消失,或是呼叫 dismissHeadingCalibrationDisplay 方法 - (void)locationManager:(CLLocationManager *) manager didUpdateHeading:(CLHeading *) newHeading
CLLocation Property CLLocationCoordinate2D coordinate typedef struct { CLLocationDegrees latitude; CLLocationDegrees longitude; } CLLocationCoordinate2D; Property CLLocationCoordinate2D coordinate NSDate *timestamp 定位時的時間 CLLocationDistance altitude 海拔高度(公尺) CLLocationSpeed speed 瞬間速度,負值表示速度不可用 meters/second CLLocationDirection course 移動方向 degrees, 0 is north, clockwise
CLLocation - (CLLocationDistance) distanceFromLocation: (const CLLocation *) location 回傳與參數location位置的距離(m)
CLHeading Property CLLocationDirection magneticHeading 裝置朝向(與磁北極的角度) CLLocationDirection trueHeading NSDate *timestamp
練習 取得裝置目前的位置和方向資訊
CLGeocoder 經緯度與地址轉換 - (void)reverseGeocodeLocation:(CLLocation *) location completionHandler: (CLGeocodeCompletionHandler)completionHandle r - (void)geocodeAddressString:(NSString *) addressString completionHandler: (CLGeocodeCompletionHandler)completionHandle r - (void)cancelGeocode Cancels a pending geocoding request.
CLGeocodeCompletionHandler typedef void (^CLGeocodeCompletionHandler) (NSArray *placemark, NSError *error);
CLPlacemark Placemark Attributes NSString *name NSDictionary *addressDictionary NSString *administrativeArea The state associated with the placemark NSString *subAdministrativeArea Additional administrative area information for the placemark NSString *country
CLPlacemark NSString *postalCode NSString *locality The city associated with the placemark. NSString *subLocality Additional city-level information for the placemark NSString *thoroughfare The street address associated with the placemark. NSString *subThoroughfare Additional street-level information for the placemark.
範例 CLGeocoder *geo=[[CLGeocoder alloc]init]; [geo reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) { if (error){ NSLog(@"Geocode failed with error: %@", error); return; } NSLog(@"Received placemarks: %@", placemarks[0]); }];
Map
MapKit 加入MapKit framework 將MapView拉到View上 Type:地圖模式 Map Satellite Hybrid
MKMapView Property MKMapType mapType BOOL zoomEnabled enum { MKMapTypeStandard, MKMapTypeSatellite, MKMapTypeHybrid }; typedef NSUInteger MKMapType; Property MKMapType mapType BOOL zoomEnabled BOOL scrollEnabled BOOL pitchEnabled //傾斜地圖平面 BOOL rotateEnabled BOOL showsUserLocation (是否嘗試顯示使用者位置, 可能不可見) BOOL userLocationVisible (read-only)(使用者位置是 否在目前地圖上可見) MKUserLocation *userLocation The annotation object representing the user’s current location.
MKMapView MKCoordinateRegion region map view目前顯示的區域 CLLocationCoordinate2D centerCoordinate - (void) setRegion:(MKCoordinateRegion)region animated:(BOOL) animated 設定map view顯示範圍 - (void) setCenterCoordinate:(CLLocationCoordinate2D ) coordinate animated:(BOOL) animated 設定地圖中心點經緯度
MKCoordinateRegion latitudeDelta / longitudeDelta typedef struct { CLLocationCoordinate2D center; MKCoordinateSpan span; } MKCoordinateRegion; typedef struct { CLLocationDegrees latitude; CLLocationDegrees longitude; } CLLocationCoordinate2D; typedef double CLLocationDegrees; typedef struct { CLLocationDegrees latitudeDelta; CLLocationDegrees longitudeDelta; } MKCoordinateSpan; latitudeDelta / longitudeDelta The amount of north-to-south / east-to-west distance (measured in degrees) to display on the map. One degree of latitude is approximately 111 kilometers. One degree of longitude spans a distance of approximately 111 kilometers at the equator but shrinks to 0 kilometers at the poles.
MKCoordinateSpan mapSpan; mapSpan.latitudeDelta=0.005; mapSpan.longitudeDelta=0.005; MKCoordinateRegion mapRegion; mapRegion.center=newLocation.coordinate; mapRegion.span=mapSpan; mapView.region=mapRegion;
MKMapView 經緯度與view座標轉換 - (CGPoint)convertCoordinate:(CLLocationCoordina te2D) coordinate toPointToView:(UIView *) view 經緯度轉換成指定view的坐標 - (CLLocationCoordinate2D)convertPoint:(CGPoint) point toCoordinateFromView:(UIView *)view 指定view的坐標轉換成經緯度
MKMapView 定義地圖相關事件 載入地圖相關事件 MKMapView拉線到實作MKMapViewDelegate的ViewController 定義地圖相關事件 載入地圖相關事件 (void)mapViewWillStartLoadingMap:(MKMapView *) mapView (void)mapViewDidFinishLoadingMap:(MKMapView *) mapView (void)mapViewDidFailLoadingMap:(MKMapView *) mapView withError:(NSError *)error
MKMapViewDelegate 追蹤使用者位置相關事件 (void)mapViewWillStartLocatingUser:(MKMapView *) mapView (void)mapViewDidStopLocatingUser:(MKMapView *) mapView (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error Tells the delegate that an attempt to locate the user’s position failed. (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
練習 隨著位置改變地圖跟著移動
標記與註記 由一個data model與view組成 Data model:指定標題副標題和經緯度 View:data model視覺化呈現 MKAnnotation Protocol View:data model視覺化呈現 MKAnnotationView 地圖標記由MKMapViewDelegate的 mapView:viewForAnnotation:呈現
MKAnnotation Protocol 提供標記相關資訊給map view CLLocationCoordinate2D coordinate - (void) setCoordinate: (CLLocationCoordinate2D) newCoordinate - (NSString *)title - (NSString *)subtitle
myAnnotation.h myAnnotation.m #import <Foundation/Foundation.h> #import <CoreLocation/CoreLocation.h> #import <MapKit/MapKit.h> @interface myAnnotation : NSObject<MKAnnotation> -(id)initWithCoordinate:(CLLocationCoordinate2D)theCoordinate title:(NSString *) theTitle subtitle:(NSString *) theSubtitle; @property(nonatomic,assign)CLLocationCoordinate2D coordinate; @property(nonatomic,copy)NSString * title; @property(nonatomic,copy)NSString * subtitle; @end myAnnotation.h #import "myAnnotation.h” @implementation myAnnotation -(id)initWithCoordinate:(CLLocationCoordinate2D)theCoordinate title:(NSString *) theTitle subtitle:(NSString *) theSubtitle{ self=[super init]; self.coordinate=theCoordinate; self.title=theTitle; self.subtitle=theSubtitle; return self; } @end myAnnotation.m
MKMapView 地圖標記 標示 選取 移除 Property NSArray *annotations NSArray *selectedAnnotations - (void)addAnnotation:(id < MKAnnotation >) annotation - (void)addAnnotations:(NSArray *) annotations - (void)removeAnnotation:(id < MKAnnotation >) annotation - (void)removeAnnotations:(NSArray *)annotations
MKMapView - (void)selectAnnotation:(id < MKAnnotation >) annotation animated:(BOOL)animated 選取指定的標記,並顯示callout view - (void)deselectAnnotation:(id < MKAnnotation >) annotation animated:(BOOL)animated 取消選取指定的標記,並讓callout view消失
地圖加入標記 CLLocationCoordinate2D coord; coord.latitude=25; coord.longitude=121.25; myAnnotation *my=[[myAnnotation alloc]initWithCoordinate:coord title:@"test" subtitle:@"subtest"]; [self.myMap addAnnotation:my];
練習 在目前位置加入標記
標記與註記 由一個data model與view組成 Data model:指定標題副標題和經緯度 View:data model視覺化呈現 MKAnnotation Protocol View:data model視覺化呈現 MKAnnotationView 地圖標記由MKMapViewDelegate的 mapView:viewForAnnotation:呈現
MKAnnotationView - (id)initWithAnnotation:(id <MKAnnotation>) annotation reuseIdentifier: (NSString *) reuseIdentifier Property BOOL enabled 預設YES. NO:annotation view會忽略觸控事件,且不能選取 UIImage *image id <MKAnnotation> annotation The annotation object currently associated with the view. BOOL highlighted
MKAnnotationView Property CGPoint centerOffset CGPoint calloutOffset 標記中心點坐標偏移量 CGPoint calloutOffset callout bubble位置的移動偏移量 若設定為 (0, 0)表示callout bubble會放置在標記frame的上方 中間位置
MKAnnotationView Property BOOL canShowCallout UIView *leftCalloutAccessoryView UIView *rightCalloutAccessoryView
MKMapView - (MKAnnotationView *) dequeueReusableAnnotationViewWithIdentifier:(N SString *) identifier 回傳可重複使用的annotation view
MKMapViewDelegate 標記相關 (MKAnnotationView *)mapView:(MKMapView *) mapView viewForAnnotation:(id <MKAnnotation>) annotation 要客製化標記需覆寫此方法,回傳客製化的 MKAnnotationView 這個可能回傳 MKUserLocation 物件表示目前位置 (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views 一個或多個annotation views被加入,此方法會被呼叫
MKMapViewDelegate - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control - (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *) view - (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *) view
練習 在目前位置加入標記,標記 為自行定義之樣式,標記中 顯示位置資訊
-(MKAnnotationView. )mapView:(MKMapView -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { MKAnnotationView *view= [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"myanno"]; if(!view) view=[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"myanno"]; view.image=[UIImage imageNamed:@"apple1.png"]; view.canShowCallout=YES; view.rightCalloutAccessoryView= [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; } return view;
MKPinAnnotationView Property BOOL animatesDrop 此標記出現在視窗上時是否有動畫 MKPinAnnotationColor pinColor 設定預設大頭針標記頭的顏色 enum { MKPinAnnotationColorRed = 0, //destination points MKPinAnnotationColorGreen, //starting points MKPinAnnotationColorPurple //user-specified points }; typedef NSUInteger MKPinAnnotationColor;
-(MKAnnotationView. )mapView:(MKMapView -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { MKPinAnnotationView *view=(MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"myanno"]; if(!view) view=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"myanno"]; view.pinColor=MKPinAnnotationColorPurple; view.animatesDrop=YES; view.rightCalloutAccessoryView= [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; } return view;