關於大頭針和覆蓋物的一些知識

       在百度地圖的開發過程當中,通常都是根據model類給出的經緯度在地圖上添加大頭針,以及當選中當前的大頭針的時候在此添加覆蓋物以標記這個位置就是當前選中的,與此同時,還要根據選中的大頭針來肯定選中的是那個model類的對象。git

需求一數組

      地圖中通常都有多個大頭針的對象,怎麼樣將全部的大頭針都顯示在地圖的顯示範圍以內,而且以一個合適的範圍,首先的思路是這種 :取出全部的大頭針對象,根據大頭針對象的經緯度算出當前全部大頭針的最大、最小的經緯度,而後 (最大經緯度 + 最小經緯度)/2,就能夠獲得當前顯示範圍的中心點的經緯度,最大經緯度-最小經緯度  就能夠獲得地圖的顯示範圍。函數

 

上代碼測試

-(void) centerMapWithArray:(NSArray *)routes {
    
    CLLocationDegrees maxLat = 0.0;
    CLLocationDegrees maxLon = 0.0;
    CLLocationDegrees minLat = 0.0;
    CLLocationDegrees minLon = 0.0;
    for(int idx = 0; idx < routes.count; idx++)
    {
        BMKPointAnnotation* currentLocation = [routes objectAtIndex:idx];

        if (idx == 0) {                //以第一個座標點作初始值
            
            minLat = currentLocation.coordinate.latitude;
            maxLat = currentLocation.coordinate.latitude;
            minLon = currentLocation.coordinate.longitude;
            maxLon = currentLocation.coordinate.longitude;
        }else{
            //對比篩選出最小緯度,最大緯度;最小經度,最大經度
            minLat = MIN(minLat, currentLocation.coordinate.latitude);
            maxLat = MAX(maxLat, currentLocation.coordinate.latitude);
            minLon = MIN(minLon, currentLocation.coordinate.longitude);
            maxLon = MAX(maxLon, currentLocation.coordinate.longitude);
        }
    }
    
    //計算中心點
    CLLocationCoordinate2D centCoor;
    centCoor.latitude = (CLLocationDegrees)((maxLat+minLat) * 0.5f);
    centCoor.longitude = (CLLocationDegrees)((maxLon+minLon) * 0.5f);
    BMKCoordinateSpan span;
    //計算地理位置的跨度,*1.1 防止標註恰好在地圖的邊緣
    span.latitudeDelta = (maxLat - minLat)*1.1;
    span.longitudeDelta = (maxLon - minLon)*1.1;
    //得出數據的座標區域
    //    BMKCoordinateRegion region = BMKCoordinateRegionMake(centCoor, span);
    BMKCoordinateRegion region;
    region.center = centCoor;
    region.span = span;
    [_mapView setRegion:region animated:YES];
   
}

經過查看百度地圖的API,能夠知道動畫

/// 當前地圖View的已經添加的標註數組
@property (nonatomic, readonly) NSArray *annotations;

這個數組返回當前地圖View中的標註,routes  須要把 self.mapView.annotations做爲參數。你們注意到計算顯示範圍的時候 *1.1,這是防止大頭針剛好在地圖的最邊緣,不合適。atom

尼瑪,寫完以後發現百度地圖提供了相應的方法:spa

/**
 *設置地圖使顯示區域顯示全部annotations,若是數組中只有一個則直接設置地圖中心爲annotation的位置
 *@param annotations 指定的標註
 *@param animated 是否啓動動畫
 */
- (void)showAnnotations:(NSArray *)annotations animated:(BOOL)animated;

系統的方法仍是存在有些標註在當前顯示範圍的最邊緣,全部仍是採起了上面一種方式來處理這種狀況。code

需求二對象

     點擊大頭針的話,須要肯定當前選中的大頭針對象對應的model類的哪個對象。思路以下,若是能夠拿到選中大頭針的對象的經緯度的話,就能夠根據經緯度肯定對應的model類對象。接口

百度地圖提供了這個方法

 

/**
 *當選中一個annotation views時,調用此接口
 *@param mapView 地圖View
 *@param views 選中的annotation views
 */
- (void)mapView:(BMKMapView *)mapView didSelectAnnotationView:(BMKAnnotationView *)view;

   在這個方法中能夠獲取到BMKAnnotationView和BMKMapView對應的對象,顯然BMKAnnotationView對於解決問題是有用的。

查看API,BMKAnnotationView並無經度或者緯度的屬性...可是有這個屬性

///關聯的annotation
@property (nonatomic, strong) id <BMKAnnotation> annotation;

查看BMKAnnotation對應的API

//
//  Copyright 2011 Baidu Inc. All rights reserved.
//

#import <CoreGraphics/CoreGraphics.h>
#import <CoreLocation/CoreLocation.h>
#import <Foundation/Foundation.h>

/// 該類爲標註點的protocol,提供了標註類的基本信息函數
@protocol BMKAnnotation <NSObject>

///標註view中心座標.
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;

@optional

有coordinate屬性,經過這個屬性就能夠獲取到選中的大頭針對應的經緯度,而後根據經緯度就能夠確認此大頭針對應的model類對象。

需求三

選中大頭針的時候要在這裏加一個圓形的覆蓋物,以標註選中的狀態。這個需求其實不難,系統有添加覆蓋物的方法 

/**
 *向地圖窗口添加Overlay,須要實現BMKMapViewDelegate的-mapView:viewForOverlay:函數來生成標註對應的View
 *@param overlay 要添加的overlay
 */
- (void)addOverlay:(id <BMKOverlay>)overlay;

須要BMKOverlay的對象,

/**
 *根據中心點和半徑生成圓
 *@param coord 中心點的經緯度座標
 *@param radius 半徑,單位:米
 *@return 新生成的圓
 */
+ (BMKCircle *)circleWithCenterCoordinate:(CLLocationCoordinate2D)coord
                                  radius:(CLLocationDistance)radius;

這裏圓形覆蓋物的半徑須要的參數單位爲:米。怎麼肯定這個參數的大小呢???

在網上找了半天也沒有發現有養分的信息,只能用笨的方法了。

添加的時候只能靠臉一個個的大小作測試,找到一個合適的大小好比:currectRadius,而後獲取到當前顯示範圍的經度或者緯度,這樣的話就能夠獲取的一個比例,找到這個合適的比例的話,就能夠肯定圓形覆蓋物的半徑大小了。

需求四

添加完成覆蓋物以後,當地圖的顯示範圍變化的時候,就會出現覆蓋物的範圍已經不合適了,顯示範圍變小的時候,覆蓋物的半徑就太大了,反之,亦然。

無論地圖顯示範圍多大,覆蓋物大小不變。

API中有幾個方法是和地圖顯示範圍變化有關係的

/**
 *地圖區域即將改變時會調用此接口
 *@param mapview 地圖View
 *@param animated 是否動畫
 */
- (void)mapView:(BMKMapView *)mapView regionWillChangeAnimated:(BOOL)animated;

/**
 *地圖區域改變完成後會調用此接口
 *@param mapview 地圖View
 *@param animated 是否動畫
 */
- (void)mapView:(BMKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;

需求的是覆蓋物的半徑大小要隨着地圖顯示範圍的變化而時時改變,這兩個方法均可以實現改變半徑,可是和需求並不符合接着找吧。

/**
 *地圖渲染每一幀畫面過程當中,以及每次須要重繪地圖時(例如添加覆蓋物)都會調用此接口
 *@param mapview 地圖View
 *@param status 此時地圖的狀態
 */
- (void)mapView:(BMKMapView *)mapView onDrawMapFrame:(BMKMapStatus*)status

這個方法是繪圖的時候調用的,地圖顯示範圍變化的時候,覆蓋物也要重繪,這樣的話,這個方法能夠實現這個需求。這裏以圓形覆蓋物爲例,實現的代碼在這裏。

for (BMKOverlayView *lay in mapView.overlays) {
        if ([lay isKindOfClass:[BMKCircle class]]) {//取到當前顯示的覆蓋物(我這裏只有一個)
            BMKCircle *circleView = (BMKCircle *)lay;
            circleView.radius = mapView.region.span.longitudeDelta*合適的比例;//改變覆蓋物的半徑大小
        }
    }

這些是遇到的一些問題和解決方案,但願有其餘方案的朋友能夠賜教。

相關文章
相關標籤/搜索