关于大头针和覆盖物的一些知识

       在百度地图的开发过程当中,通常都是根据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*合适的比例;//改变覆盖物的半径大小
        }
    }

这些是遇到的一些问题和解决方案,但愿有其余方案的朋友能够赐教。

相关文章
相关标签/搜索