iOS 百度地图在房地产项目中的应用

Posted xj_love

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS 百度地图在房地产项目中的应用相关的知识,希望对你有一定的参考价值。

1.公司的项目是面向房地产的,包含新房(全国多个分公司),存租房(与建行建方的合作)项目,所以地图与看房相结合比较多,之前为了进度,地图这一块的业务都是H5实现,现在稳定下来后,H5的体验度不是很高,所以地图这一块全部换成原生。这篇文章也是做个探索和总结,以便大家一起参考学习。
2.地图采用百度地图,主要功能包括:定位+替换大头针图标,两点连线及采用自定义图片样式,导航,点标注,自定义标注UI,点击事件,点聚合的算法(重点)+优化

一. 定位+替换大头针图标

#pragma mark - 定位当前位置
- (void)initLocation

    ///BMKLocationManager类。初始化之前请设置 BMKLocationAuth 中的APIKey,否则将无法正常使用服务.
    _locationManager = [[BMKLocationManager alloc] init];
    
    _locationManager.delegate = self;
    
    _locationManager.coordinateType = BMKLocationCoordinateTypeBMK09LL;
    _locationManager.distanceFilter = kCLDistanceFilterNone;
    _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    _locationManager.activityType = CLActivityTypeAutomotiveNavigation;
    _locationManager.pausesLocationUpdatesAutomatically = NO;
    _locationManager.allowsBackgroundLocationUpdates = YES;
    _locationManager.locationTimeout = 10;
    _locationManager.reGeocodeTimeout = 10;
    
    __weak BMKClusterAnnotationPage *weakSelf = self;
    ///单次定位。如果当前正在连续定位,调用此方法将会失败,返回NO。\\n该方法将会根据设定的 desiredAccuracy 去获取定位信息。如果获取的定位信息精确度低于 desiredAccuracy ,将会持续的等待定位信息,直到超时后通过completionBlock返回精度最高的定位信息。\\n可以通过 stopUpdatingLocation 方法去取消正在进行的单次定位请求
    [_locationManager requestLocationWithReGeocode:YES withNetworkState:YES completionBlock:^(BMKLocation * _Nullable location, BMKLocationNetworkState state, NSError * _Nullable error) 
        BMKClusterAnnotationPage *strongSelf = weakSelf;
        MyLocation * loc = [[MyLocation alloc]initWithLocation:location.location withHeading:nil];
        [strongSelf addLocToMapView:loc];
    ];
    
    //替换大头针图片方法之一
    BMKLocationViewDisplayParam *displayParam = [[BMKLocationViewDisplayParam alloc] init];
    displayParam.locationViewOffsetX=0;//定位偏移量(经度)
    displayParam.locationViewOffsetY=0;//定位偏移量(纬度)
    displayParam.isAccuracyCircleShow=NO;//经度圈是否显示
    //这里替换自己的图标路径,必须把图片放到百度地图SDK的Resources/mapapi.bundle/images 下面
    //还有一种方法就是获取到_locationView之后直接设置图片
    displayParam.locationViewImgName=@"pin_red";
    [_mapView updateLocationViewWithParam:displayParam];


- (void)addLocToMapView:(MyLocation *)loc

    [_mapView updateLocationData:loc];
    [_mapView setCenterCoordinate:loc.location.coordinate animated:YES];
    [_mapView setZoomLevel:18];
    _mapView.showsUserLocation = YES; //一定要设置这个参数为YES,不然大头针不出来

二.两点连线及采用自定义图片样式

#pragma mark - 两点之间划线
- (void)lineTwoAction:(MyLocation*)myLoc andOther:(MyLocation*)otherLoaction
    
    CLLocationCoordinate2D coors[2] = 0;
    
    coors[1].latitude = myLoc.location.coordinate.latitude;
    coors[1].longitude = myLoc.location.coordinate.longitude;//定位坐标1
    
    coors[0].latitude = otherLoaction.location.coordinate.latitude;
    coors[0].longitude = otherLoaction.location.coordinate.longitude;//定位坐标2
    
    BMKPolyline *polyLine = [BMKPolyline polylineWithCoordinates:coors count:2];
    [_mapView addOverlay:polyLine];


//一定要实现这个代理方法
- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay
    
    //连线,设置宽度,颜色等
    BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithPolyline:overlay];
    polylineView.strokeColor = [[UIColor purpleColor] colorWithAlphaComponent:1];
    polylineView.lineWidth = 10.0;
    
    //使用自定义图片连线
    /*
    BMKMapPoint point;
    point.x = 0;
    point.y = 0;
    [polylineView renderTexturedLinesWithPoints:&point pointCount:2 lineWidth:10 textureID:[polylineView loadStrokeTextureImage:[UIImage imageNamed:@"xxx"]] looped:YES];
     */
    
    return polylineView;

三.导航

我们做的导航没有内置在自己的APP里,而是调起第三方地图软件,进行导航。包括苹果原生地图,高德地图,百度地图。需传入起点终点经纬度,调起代码:

-(void)navigation:(NSDictionary*)param

//start_lng: 起点经度
//start_lat: 起点维度
//end_lng: 终点经度
//end_lat: 终点维度
//end_name: 终点楼盘名称
    
    NSString *start_lng = [NSString stringWithFormat:@"%@", param[@"start_lng"]];
    NSString *start_lat = [NSString stringWithFormat:@"%@", param[@"start_lat"]];
    NSString *start_name = [NSString stringWithFormat:@"%@", param[@"start_address"]];
    NSString *end_lng = [NSString stringWithFormat:@"%@", param[@"end_lng"]];
    NSString *end_lat = [NSString stringWithFormat:@"%@", param[@"end_lat"]];
    NSString *end_name = [NSString stringWithFormat:@"%@", param[@"end_name"]];
    

    UIAlertController *avc = [UIAlertController alertControllerWithTitle:@"请选择导航地图" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
    
    UIApplication *app = [UIApplication sharedApplication];
    
    // -canOpenURL: failed for URL: "iosamap://navi" - error: "未能完成操作。(“OSStatus”错误 -10814。)"
    if ([app canOpenURL:[NSURL URLWithString:@"map://"]]) 
        
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"使用苹果自带地图导航" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) 
            
            
            CLLocationCoordinate2D coords1 = CLLocationCoordinate2DMake(start_lat.floatValue,start_lng.floatValue);
            CLLocationCoordinate2D coords2 = CLLocationCoordinate2DMake(end_lat.floatValue,end_lng.floatValue);
            
            MKMapItem *currentLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:coords1 addressDictionary:nil]];
            currentLocation.name = start_name;
            
            MKMapItem *toLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:coords2 addressDictionary:nil]];
            toLocation.name = end_name;
            
            NSArray *items = [NSArray arrayWithObjects:currentLocation, toLocation, nil];
            
            NSDictionary *options = @ MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving, MKLaunchOptionsMapTypeKey: [NSNumber numberWithInteger:MKMapTypeStandard], MKLaunchOptionsShowsTrafficKey:@YES ; //打开苹果自身地图应用,并呈现特定的item
            
            [MKMapItem openMapsWithItems:items launchOptions:options];
        ];
        
        [avc addAction:action];
        
    
    
    if ([app canOpenURL:[NSURL URLWithString:@"iosamap://navi"]]) 
        
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"使用高德地图导航" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) 
            
            NSString *url = [[NSString stringWithFormat:@"iosamap://path?sourceApplication=applicationName&sid=BGVIS1&slat=%@&slon=%@&sname=%@&did=BGVIS2&dlat=%@&dlon=%@&dname=%@&dev=0&t=0", start_lat,start_lng,start_name,end_lat,end_lng,end_name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            
//            NSString *url = [[NSString stringWithFormat:@"iosamap://navi?sourceApplication=applicationName&backScheme=applicationScheme&poiname=%@&poiid=BGVIS&lat=%@=%@&dev=1&style=2", end_name, end_lat, end_lng] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];

        ];
        
        [avc addAction:action];
        
    
    
    if ([app canOpenURL:[NSURL URLWithString:@"baidumap://map"]]) 
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"使用百度地图导航" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) 
            
            NSString *url = [[NSString stringWithFormat:@"baidumap://map/direction?origin=latlng:%@,%@|name:%@&destination=latlng:%@,%@|name:%@&mode=driving&src=webapp.navi.yourCompanyName.yourAppName", start_lat,start_lng,start_name,end_lat,end_lng,end_name]
                             stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
            
        ];
        
        [avc addAction:action];
        
    
    
    UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) 
    ];
    [avc addAction:cancel];
    
    if (kIsIPAD) 
        
        UIPopoverController *poc = [[UIPopoverController alloc] initWithContentViewController:avc];
        [poc presentPopoverFromRect:CGRectMake(SCREEN_WIDTH / 2.0, SCREEN_HEIGHT - 60, 200, 200) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
        
//        avc.modalPresentationStyle = UIModalPresentationPopover;
//        avc.popoverPresentationController.sourceView = self.view;
//        avc.popoverPresentationController.sourceRect = CGRectMake(SCREEN_WIDTH / 2.0, SCREEN_HEIGHT - 60, 200, 200);
//        avc.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionDown;
//        [self presentViewController:avc animated:YES completion:nil];
        
    else
        
        [self presentViewController: avc animated: YES completion: nil];
    

四.点标注+自定义标注UI+点击事件

1.需要用到的相关代理

/**
 地图加载完成时会调用此方法
 
 @param mapView 当前地图View
 */
- (void)mapViewDidFinishLoading:(BMKMapView *)mapView 
    [self updateClusters];

/**
 地图渲染每一帧画面过程中,以及每次需要重新绘制地图时(例如添加覆盖物)都会调用此方法
 
 @param mapView 地图View
 @param status 地图状态
 */
- (void)mapView:(BMKMapView *)mapView onDrawMapFrame:(BMKMapStatus *)status 
    if (_clusterZoom != 0 && _clusterZoom != (NSInteger)mapView.zoomLevel) 
        [self updateClusters];
    

2.添加标注,至于__block NSArray *array = [_clusterManager getClusters:_clusterZoom]里面的对象,可以参考百度demo BMKClusterAnnotationPage类里面。不过也只是自定义的一个NSObject对象。

#pragma mark - Clusters
- (void)updateClusters 
    _clusterZoom = (NSInteger)_mapView.zoomLevel;
    @synchronized(_clusterManager.clusterCaches) 
        NSMutableArray *clusters = [_clusterManager.clusterCaches objectAtIndex:(_clusterZoom - 3)];
        if (clusters.count > 0) 
            /**
             移除一组标注
             
             @param annotations 要移除的标注数组
             */
            [_mapView removeAnnotations:_mapView.annotations];
            //将一组标注添加到当前地图View中
            [_mapView addAnnotations:clusters];
         else 
            dispatch_async(dispatch_get_global_queue(0, 0), ^
                ///获取聚合后的标注
                __block NSArray *array = [_clusterManager getClusters:_clusterZoom];
                dispatch_async(dispatch_get_main_queue(), ^
                    for (BMKCluster *item in array) 
                        ClusterAnnotation *annotation = [[ClusterAnnotation alloc] init];
                        //设置标注的经纬度坐标
                        annotation.coordinate = item.coordinate;
                        annotation.size = item.size;//标识
                        annotation.title = @"";  //为空点击就没有气泡弹出
                        [clusters addObject:annotation];
                    
                    /**
                     移除一组标注
                     @param annotations 要移除的标注数组
                     */
                    [_mapView removeAnnotations:_mapView.annotations];
                    //将一组标注添加到当前地图View中
                    [_mapView addAnnotations:clusters];
                );
            );
        
    

3.根据anntation生成对应的View(就是自定义的大头针)

#pragma mark - BMKMapViewDelegate
// 根据anntation生成对应的View
- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id <BMKAnnotation>)annotation 
    ClusterAnnotation *cluster = (ClusterAnnotation*)annotation;
    BMKPinAnnotationView *annotationView = [[BMKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationViewIdentifier];
    
    if (cluster.size > 1) 
        annotationView.bounds = CGRectMake(0, 0, 100, 96);
     else 
        annotationView.bounds = CGRectMake(0, 0, 100, 37);
    
    annotationView.image = nil;
    
    UIView *backView = [[UIView alloc] init];
    
    UIImageView *tapImageView = [[UIImageView alloc] init];
    tapImageView.image = [UIImage imageNamed:@"marker-golden-build"];
    
    if (cluster.size > 1)  //根据标识,来绘制不同的图片
        backView.frame = CGRectMake(0, 0, 100, 96);
        tapImageView.frame = CGRectMake(33, 17, 34, 58);
        tapImageView.image = [UIImage imageNamed:@"marker-golden-build"];
        annotationView.bounds = CGRectMake(0, 0, 100, 96);
        tapImageView.image = [UIImage imageNamed:@"marker-golden-build"];
        
        UIImageView *bottomImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"marker-golden-circle"]];
        bottomImgView.frame = CGRectMake(24, tapImageView.frame.origin.y+58,52, 21);
        [backView addSubview:bottomImgView];
     else 
        backView.frame = CGRectMake(0, 0, 100, 37);
        tapImageView.frame = CGRectMake(32, 17, 25, 20);
        annotationView.bounds = CGRectMake(0, 0, 100, 37);
        tapImageView.image = [UIImage imageNamed:@"branch-build"];
        
    
    
    [backView addSubview:tapImageView];
    
    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 15)];
    titleLabel.backgroundColor = [UIColor orangeColor];
    titleLabel.text = [NSString stringWithFormat:@"我有%ld套房源", cluster.size];
    titleLabel.font = [UIFont systemFontOfSize:14];
    titleLabel.textAlignment = NSTextAlignmentCenter;
    [backView addSubview:titleLabel];
    
    [annotationView addSubview:backView];
        
    annotationView.draggable = YES;
    annotationView.annotation = annotation;
    
    return annotationView;

4.踩坑集合:

4.1 如果想点击图标弹出气泡,在第二步annotation.title = @"";时一定要传值,不然无效

4.2 如果annotation.title = @""为空,图标自带的点击事件就不会相应

4.3 如果要点击事件,又不想气泡,在自定义图标上加个手势事件

4.4 百度有个自带的大头针,annotationView.image = nil; 除去

4.5 要想点击事件有效,必须正确设置annotationView.bounds和自定义的UI大小一致;

4.6 annotationView.image = nil;和annotationView.bounds;要放在自定义控件前面定义

五.点聚合的算法(重点)+优化

以上是关于iOS 百度地图在房地产项目中的应用的主要内容,如果未能解决你的问题,请参考以下文章

集成百度地图SDK(swift)

百度地图整体封装大头针

百度地图常用功能

百度地图jsapi 自定义大头针的方法

总结一下百度地图 定位 大头针 和划线和城市检索的功能

iOS开发中地图开发的简单应用