高德地圖附近停車場服務

weixin_33890499發表於2017-06-20

功能:

1、使用者定位追蹤
2、自定義使用者當前位置大頭針
3、新增和移除附近停車場大頭針
4、跳動動畫

注意事項:

1、專案使用需進行二次封裝
2、用前請配置高德地圖AppKey

實現過程

一、新增地圖

- (void)creatMapView {
    _mapView = [[MAMapView alloc]initWithFrame:self.view.bounds];
    _mapView.delegate = self;
    _mapView.showsCompass = NO;
    _mapView.showsScale = NO;
    _mapView.rotateEnabled = NO;
    _mapView.showsUserLocation = YES;
    _mapView.userTrackingMode = MAUserTrackingModeFollow;
    _mapView.customizeUserLocationAccuracyCircleRepresentation = YES;
    [_mapView setZoomLevel:15.1 animated:NO];
    [self.view addSubview:_mapView];
}

如下兩句開啟定位追蹤功能

_mapView.showsUserLocation = YES;
_mapView.userTrackingMode = MAUserTrackingModeFollow;

如下程式碼,隱藏高德SDK預設小藍點,自定義使用者頭像為當前位置

_mapView.customizeUserLocationAccuracyCircleRepresentation = YES;

二、螢幕中間新增一個“針”

1、新增螢幕中間位置的“針”

- (void)setUpCenterAnnotationView {
    //新增地圖中間圖示
    UIImage *image = [UIImage imageNamed:@"position"];
    
    float origin_X = (self.mapView.frame.size.width - image.size.width)*0.5;
    float origin_y = self.mapView.frame.size.height*0.5 - image.size.height;
    
    centerAnnotaionView = [[UIImageView alloc]initWithFrame:CGRectMake(origin_X, origin_y, image.size.width, image.size.height)];
    centerAnnotaionView.image = image;
    centerAnnotaionView.contentMode = UIViewContentModeScaleAspectFill;
    [self.mapView addSubview:centerAnnotaionView];
}

2、給iamgeView新增跳動動畫,每次請求高德地圖附近停車場的時候,新增一個跳動動畫,效果還是挺漂亮的。

//跳動動畫
- (void)centerAnnotaionAnimation {
    UIImage *centerAnnotationImage = [UIImage imageNamed:@"position"];
    
    float origin_x = (self.view.frame.size.width - centerAnnotationImage.size.width)*0.5;
    float origin_y = self.mapView.frame.size.height*0.5 - centerAnnotationImage.size.height*2+10;
    //組動畫
    CAKeyframeAnimation *anima1 = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    NSValue *value0 = [NSValue valueWithCGPoint:CGPointMake(origin_x+centerAnnotationImage.size.width/2, origin_y+centerAnnotationImage.size.height+10)];
    NSValue *value1 = [NSValue valueWithCGPoint:CGPointMake(origin_x+centerAnnotationImage.size.width/2, origin_y-30+centerAnnotationImage.size.height+10)];
    NSValue *value2 = [NSValue valueWithCGPoint:CGPointMake(origin_x+centerAnnotationImage.size.width/2, origin_y+centerAnnotationImage.size.height+10)];
    anima1.values = [NSArray arrayWithObjects:value0,value1,value2, nil];
    //組動畫
    CAAnimationGroup *groupAnimation = [CAAnimationGroup animation];
    groupAnimation.animations = [NSArray arrayWithObjects:anima1, nil];
    groupAnimation.duration = 0.5f;
    groupAnimation.fillMode = kCAFillModeForwards;
    groupAnimation.removedOnCompletion = NO;
    [centerAnnotaionView.layer addAnimation:groupAnimation forKey:@"groupAnimation"];
}

三、地圖定位回撥代理

1、設定_mapView.showsUserLocation = YES;使用者位置或者裝置方向更新後,會呼叫如下函式

/**
 * @brief 位置或者裝置方向更新後,會呼叫此函式
 * @param mapView 地圖View
 * @param userLocation 使用者定位資訊(包括位置與裝置方向等資料)
 * @param updatingLocation 標示是否是location資料更新, YES:location資料更新 NO:heading資料更新
 */
- (void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation;

2、在此方法裡面我們可以時時的獲取到使用者當前位置資訊,即使沒有網路,也會有GPS定位,將維度回撥回來

#pragma mark MAMapViewDelegate
- (void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation {
    
    NSLog(@"%d",updatingLocation);
    NSLog(@"位置更新");
    NSLog(@"當前位置:%f,%f",userLocation.location.coordinate.latitude,userLocation.location.coordinate.longitude);
    
    if (!userLocation.location || !(userLocation.location.coordinate.latitude>0)) {
        return;
    }
    
    if (!_currentLocation)
    {   //第一次進入地圖移動地圖至使用者當前位置
        _mapView.userTrackingMode = MAUserTrackingModeFollow;
        [self centerAnnotaionAnimation];
        [self POIAroundSearchRequest:[AMapGeoPoint locationWithLatitude:userLocation.location.coordinate.latitude longitude:userLocation.location.coordinate.longitude]];
    }
    
    _currentLocation = userLocation.location;
}

(1)在該方法中_currentLocation是一個全域性的屬性,用來儲存使用者當前位置的經緯度,如果專案中其他地方要用使用者經緯度可以直接拿去用;
(2)如下程式碼是首次進入地圖將地圖移動至使用者當前位置

_mapView.userTrackingMode = MAUserTrackingModeFollow;

(3)如下調螢幕中間的“針”,跳動動畫,動畫的方法我們上面已經寫好了。

[self centerAnnotaionAnimation];

(4)如下是寫的一個發起poi檢索的方法,往下我們會看到。

[self POIAroundSearchRequest:[AMapGeoPoint locationWithLatitude:userLocation.location.coordinate.latitude longitude:userLocation.location.coordinate.longitude]];

注意啦,注意啦:到這裡大家可以嘗試一下,給(3)和(4)兩行不同功能的程式碼寫一個queue,非同步處理這兩個方法看看和這樣處理有什麼區別,我也是心血來潮,嘗試了一下,大家也可以試試,一邊做動畫,一邊請求高德地圖附近停車場資訊。

四、地圖其他代理方法

直接上程式碼把,看看註釋。- removeStopAnnotaion方法是自己寫的一個移除地圖上所有大頭針的方法,往下我們會看到。

1、使用者操作地圖的代理

/**
 * @brief 地圖將要發生移動時呼叫此介面
 */
- (void)mapView:(MAMapView *)mapView mapWillMoveByUser:(BOOL)wasUserAction {
    if (wasUserAction) {
            //地圖將要移動時,移除地圖上所有附近停車場的大頭針
        [self removeStopAnnotaion];
    }
}

/**
 * @brief 地圖移動結束後呼叫此介面
 */
- (void)mapView:(MAMapView *)mapView mapDidMoveByUser:(BOOL)wasUserAction {
    if (wasUserAction)
    {
        NSLog(@"滑動地圖結束");
        //地圖滑動結束後,用當前使用者位置發起POI檢索
        [self POIAroundSearchRequest:[AMapGeoPoint locationWithLatitude:mapView.centerCoordinate.latitude longitude:mapView.centerCoordinate.longitude]];
    }
}

/**
 * @brief 地圖將要發生縮放時呼叫此介面
 */
- (void)mapView:(MAMapView *)mapView mapWillZoomByUser:(BOOL)wasUserAction {
    if (wasUserAction) {
        [self removeStopAnnotaion];
    }
}

/**
 * @brief 地圖縮放結束後呼叫此介面
 */
- (void)mapView:(MAMapView *)mapView mapDidZoomByUser:(BOOL)wasUserAction {
    NSLog(@"地圖縮放結束");
    if (wasUserAction) {
        [self POIAroundSearchRequest:[AMapGeoPoint locationWithLatitude:mapView.centerCoordinate.latitude longitude:mapView.centerCoordinate.longitude]];
    }
}

wasUserAction是指使用者操作時的回撥,如果wasUserAction是NO,則不做任何處理,高德地圖載入過程中使用者不操作也會呼叫如上這些方法,所以這個欄位可以說明是不是使用者操作。

2、新增大頭針的代理

當新增大頭針的時候就會執行該代理,生成大頭針檢視。

/**
 * @brief 根據anntation生成對應的View
 */
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation {
    
    //使用者當前位置大頭針
    if ([annotation isKindOfClass:[MAUserLocation class]])
    {
        static NSString *userLocationStyleReuseIndetifier = @"userLocationStyleReuseIndetifier";
        
        MAAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:userLocationStyleReuseIndetifier];
        
        if (annotationView == nil)
        {
            annotationView = [[MAAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:userLocationStyleReuseIndetifier];
        }
        
        annotationView.canShowCallout = NO;
        annotationView.image = [UIImage imageNamed:@"heardImg_passenger_default"];
        annotationView.frame = CGRectMake(0, 0, 26, 26);
        annotationView.contentMode = UIViewContentModeScaleToFill;
        annotationView.layer.masksToBounds = YES;
        
        return annotationView;
    }
    
    //停車場位置大頭針
    else if ([annotation isKindOfClass:[MAPointAnnotation class]]) {
        static NSString *stopCarReuseIndetifier = @"stopCarReuseIndetifier";
        
        MAAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:stopCarReuseIndetifier];
        
        if (annotationView == nil)
        {
            annotationView = [[MAAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:stopCarReuseIndetifier];
        }

        annotationView.canShowCallout = YES;
        UIImage *image = [UIImage imageNamed:@"centerAnnotation"];
        annotationView.image = image;
        annotationView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
        annotationView.contentMode = UIViewContentModeScaleToFill;
        annotationView.layer.masksToBounds = YES;
        annotationView.centerOffset = CGPointMake(0, -0.5*image.size.height);
        
        return annotationView;
    }
    
    return nil;
}

五、自定義的一些私有方法

1、移除地圖上所有的停車場大頭針的方法

要注意同時訪問self.dataSource,會造成資料錯亂,有些大頭針移除不掉的問題。所以需要先建立一個陣列接收需要移除的大頭針,self.dataSource只儲存最新需要顯示的大頭針資料。

//移除地圖上所有的停車場大頭針
- (void)removeStopAnnotaion {
    [UIView animateWithDuration:.5 animations:^{
        //用一個陣列去接收需要移除的大頭針
        NSMutableArray *removeAnnotations = [[NSMutableArray alloc]init];
        //除了當前位置的大頭針,其餘的都需要移除
        [removeAnnotations addObjectsFromArray:self.mapView.annotations];
        [removeAnnotations removeObject:self.mapView.userLocation];
        //移除需要移除的大頭針
        [self.mapView removeAnnotations:removeAnnotations];
        
    } completion:^(BOOL finished) {
        [self centerAnnotaionAnimation];
    }];
}

2、發起poi檢索的方法

//發起poi檢索
- (void)POIAroundSearchRequest:(AMapGeoPoint *)point {
    //取消所有未回撥的請求,防止多次疊加請求,防止造成資料來源錯亂
    [self.searchAPI cancelAllRequests];
    //地圖移動結束,請求高德地圖附近停車場資訊
    AMapPOIAroundSearchRequest *request = [[AMapPOIAroundSearchRequest alloc]init];
    request.keywords = @"停車庫";
    request.radius = 3000;
    request.location = point;
    /*發起搜尋*/
    [self.searchAPI AMapPOIAroundSearch:request];
}

self.searchAPI是一個全域性的高德地圖POI搜尋類

3、跳動動畫

螢幕中間“針”的跳動動畫,上面已說過了。

六、高德地圖POI檢索回撥

#pragma mark AMapSearchDelegate
/**
 * @brief POI查詢回撥函式
 */
- (void)onPOISearchDone:(AMapPOISearchBaseRequest *)request response:(AMapPOISearchResponse *)response
{
    if (response.pois.count == 0) {
        NSLog(@"暫無停車場資訊");
        return;
    }

    //清空資料來源
    [self.dataSource removeAllObjects];
    
    for (AMapPOI *poi in response.pois) {
        NSLog(@"%@",poi.name);
        NSLog(@"%@",poi.address);
        
        MAPointAnnotation *anotation = [[MAPointAnnotation alloc]init];
        anotation.title = poi.name;
        anotation.subtitle = poi.address;
        anotation.coordinate = CLLocationCoordinate2DMake(poi.location.latitude, poi.location.longitude);
        [self.dataSource addObject:anotation];
    }
    //新增附近車庫大頭針
    [self.mapView addAnnotations:self.dataSource];
}

self.dataSource是一個全域性的可變陣列,使用者儲存資料來源,有了資料來源我們可以做我們想做的操作。
通過此資料來源你也可以將附近的停車場資訊顯示在一個tableView上,提供使用者選擇,大多數專案多有這樣做的,都是大同小異,只要有了資料,其他只是展示資料、重新整理資料了。

最後附上效果圖和github地址大家可以克隆下來看看,有不多的地方請多多指教。
此外提醒大家看demo的時候不要忘了配置自己的AppKey哦,這玩意我就不給你提供了。

2056220-e91583a230db5e22.PNG
附近停車場.PNG

https://github.com/Mexiang/GaoDeMapParkService

相關文章