「就是有很多人搞不清楚東西南北…」,老闆一臉平淡的說著
「好吧,按下按鈕之後,讓使用者看著手機知道手機畫面的上方就是他面朝方向…收到」碼農準備出動!
我這邊的用法呢,因為 Map 有 Map 的 View ,LocationManager 也有自己獨立的 Class ,所以用起來會和網路上的稍為有一點不同,以下是作法和說明
流程上大致是當畫面上有需要更新這一個資訊時,再開啟更新GPS資料,一但有抓到了新的資料後就把更新關掉,以節省應用程式使用的資源
在ViewController裡的某個Button內容:
- (IBAction)onClickMyLocation:(id)sender {
// 檢查是否有取得位置的權限
[[PLPermissionManager sharedInstance] checkLoctionPermission:^(BOOL access){
if(access){
self.mapView.myLocationEnabled = YES;
// 先更新 Location 取得 latitude 和 longitude.
[[PLPermissionManager sharedInstance] updatingLocation:^(CLLocationCoordinate2D updateLocationCoordinate, NSError *error) {
// 取得經緯度後再取一次方向
[[PLPermissionManager sharedInstance] updatingHeading:^(CLLocationDirection updateHeading, NSError *error) {
// 開始重繪地圖
[self moveToLocation:updateLocationCoordinate
zoom:[self.delegate zoomWithCurrentLocation]
bearing:updateHeading
selectMarker:nil];
}];
}];
}
else{
// 如果不允許的話,就顯示訊息告訴使用者blablablabla...
}
}];
}
重繪地圖的方式:
-(void)moveToLocation:(CLLocationCoordinate2D)locationCoordinate
zoom:(float)zoom
bearing:(CLLocationDirection)bearing
selectMarker:(GMSMarker*)marker {
dispatch_async(dispatch_get_main_queue(), ^{
if (CLLocationCoordinate2DIsValid(locationCoordinate))
{
// 確定經緯度可用後,使用 Google Maps 提供的方法(animateToCameraPosition)對 mapView 進行更新
// 因為我不需要改viewAngle,所以給原本的預設值。
GMSCameraPosition* position = [GMSCameraPosition cameraWithTarget:locationCoordinate zoom:zoom bearing:bearing viewingAngle:self.mapView.camera.viewingAngle];
[self.mapView animateToCameraPosition:position];
}
else
{
// 如果檢查不通過,可以顯示錯誤訊息blablabla...
}
});
}
至於實際上的UpdatingLocation和UpdatingHeading的作法也沒有很複雜:
-- LocationPermission.h 檔
@property (nonatomic,strong) CLLocationManager *locationManager;
-(void)checkLoctionPermission:(void(^)(BOOL access))access;
-(void)updatingLocation:(void(^)(CLLocationCoordinate2D updateLocationCoordinate,NSError* error))updateLocationBlock;
-(void)updatingHeading:(void(^)(CLLocationDirection updateHeading, NSError* error))updateHeadingBlock;
---
-- LocationPermission.m 檔
typedef void(^UpdateLocationBlock)(CLLocationCoordinate2D updateLocationCoordinate,NSError* error);
typedef void(^UpdateHeadingBlock)(CLLocationDirection updateHeading,NSError* error);
@interface PLPermissionManager ()<CLLocationManagerDelegate>
@property (nonatomic,copy) UpdateLocationBlock updateLocationBlock;
@property (nonatomic,copy) UpdateHeadingBlock updateHeadingBlock;
@end
@implementation PLPermissionManager
-(void)updatingLocation:(void(^)(CLLocationCoordinate2D updateLocationCoordinate,NSError* error))updateLocationBlock{
self.updateLocationBlock = updateLocationBlock; // 更新完之後的 CallBack
[self.locationManager startUpdatingLocation]; // 更新位置
}
// 當 startUpdatingLocation 被呼叫後,這個 Function 會不斷被觸發。
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
if(self.updateLocationBlock){
[manager stopUpdatingLocation];
CLLocationCoordinate2D updateCoordinate = kCLLocationCoordinate2DInvalid;
if(0 != locations.count){
updateCoordinate = [locations lastObject].coordinate;
}
self.updateLocationBlock(updateCoordinate,nil);
self.updateLocationBlock = nil;
}
}
-(void)updatingHeading:(void (^)(CLLocationDirection updateDirection, NSError * error))updateHeadingBlock {
self.updateHeadingBlock = updateHeadingBlock; // 更新完之後的 CallBack
[self.locationManager startUpdatingHeading]; // 更新方向
}
// 當 startUpdatingHeading 被呼叫後,這個 Function 會不斷被觸發。
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
if(self.updateHeadingBlock){
[manager stopUpdatingHeading];
self.updateHeadingBlock(newHeading.magneticHeading,nil);
self.updateHeadingBlock = nil;
}
}
大致上的作法就是這樣,Google到的內容講的更完整豐富
其實抓到的 newHeading 可能還會有誤差,我下面貼的文章有點出這個問題,只是沒有提供解答
如果你有興趣可以再去找找
參考: