zoukankan      html  css  js  c++  java
  • 百度地图检索以及路径规划

    代码地址如下:
    http://www.demodashi.com/demo/11030.html

    一、准备工作

    • 需要集成百度地图SDK
    • 需要申请百度地图AppKey
    • 本例子实现了POI检索以及详情检索、路线规划

    二、程序实现

    首先贴一下项目截图:

    (项目截图1)

    (项目截图2)

    POI详情:
    第一步:在Appdelegate.m中设置AppKey

    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        HouseMapTootsViewController *vc = [[HouseMapTootsViewController alloc] init];
        vc.latitude = 31.976;
        vc.longitude = 118.71;
        UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:vc];
        //配置百度地图
        [self configurationBMKMap];
        self.window.rootViewController = navi;
        [self.window makeKeyAndVisible];
        return YES;
    }
    
    #pragma mark -- 百度地图
    
    - (void)configurationBMKMap {
        
        // 要使用百度地图,请先启动BaiduMapManager
        _mapManager = [[BMKMapManager alloc] init];
        BOOL ret = [_mapManager start:@"appkey" generalDelegate:self];
        if (!ret) {
            NSLog(@"manager start failed!");
        }
    }
    

    第二步:完成代理

    #pragma mark -- BMKGeneralDelegate
    
    - (void)onGetNetworkState:(int)iError {
        if (0 == iError) {
            NSLog(@"联网成功");
        }else {
            NSLog(@"onGetNetworkState %d",iError);
        }
    }
    
    - (void)onGetPermissionState:(int)iError {
        if (0 == iError) {
            NSLog(@"授权成功");
        }else {
            NSLog(@"onGetPermissionState %d",iError);
        }
    }
    

    第三步:创建百度地图,开启用户定位(后面路线规划需要)。并且添加一个大头针,这个大头针就是你即将检索的中心点。

     self.mapView = [[BMKMapView alloc] initWithFrame:CGRectMake(0, 40+64, kScreenWidth, kScreenHeight - 40 - 64)];
        [self.view addSubview:self.mapView];
        [self.view addSubview:self.planView];
    
        
        self.locService = [[BMKLocationService alloc] init];
        self.mapView.delegate = self;
        self.locService.delegate = self;
        //定位方向模式  不能使用跟随,不然地图中心就不是大头针了
        [self.mapView setZoomLevel:16];
        self.mapView.showMapScaleBar = YES;
        self.mapView.userTrackingMode = BMKUserTrackingModeNone;
        self.mapView.showsUserLocation = YES;
        [self.locService startUserLocationService];
        CLLocationCoordinate2D coor;
        coor.latitude = self.latitude;
        coor.longitude = self.longitude;
        
        
        if (self.pointAnnotation == nil) {
            //自定义大头针
            self.pointAnnotation = [[YLAnnotationView alloc]init];
            self.pointAnnotation.coordinate = coor;
            self.pointAnnotation.title = @"房源位置";
            self.pointAnnotation.subtitle = @"点击到这里去";
            self.pointAnnotation.image = [UIImage imageNamed:@"homelocation"];
        }
        [self.mapView addAnnotation:self.pointAnnotation];
        //设置中心点
        [self.mapView setCenterCoordinate:coor];
        //检索周边设施
        self.poiSearch.delegate = self;
        
        //添加大头针后添加周边检索
        self.option.location = coor;
        self.option.pageIndex = 0;
        self.option.pageCapacity = 20;
        self.option.radius = 1500;
    
    

    第四步:在点击事件中初始化检索对象,Demo中我自己定义了一个topView用来做不同点击区分。

    #pragma mark -- YLSelectorItemViewDelegate
    
    - (void)didSelectedItems:(NSInteger)item {
        
        CLLocationCoordinate2D coor;
        coor.latitude = self.latitude;
        coor.longitude = self.longitude;
        self.seletItem = item;
        self.isFirst = YES;
    
        if (item == 1) {
            self.option.keyword = @"美食";
            BOOL flag = [self.poiSearch poiSearchNearBy:self.option];
            if(flag) {
                NSLog(@"周边检索发送成功");
            }else {
                NSLog(@"周边检索发送失败");
            }
        }else if (item == 2) {
            self.option.keyword = @"超市";
            BOOL flag1 = [self.poiSearch poiSearchNearBy:self.option];
            if(flag1) {
                NSLog(@"周边检索发送成功");
            }else {
                
            }
        }else if (item == 3) {
            self.option.keyword = @"ATM";
            BOOL flag2 = [self.poiSearch poiSearchNearBy:self.option];
            if(flag2) {
                NSLog(@"周边检索发送成功");
            }else {
                NSLog(@"周边检索发送失败");
            }
        }else if (item == 4) {
            self.option.keyword = @"购物";
            BOOL flag3 = [self.poiSearch poiSearchNearBy:self.option];
            if(flag3) {
                NSLog(@"周边检索发送成功");
            }else {
                NSLog(@"周边检索发送失败");
            }
        }
     
    }
    
    

    第五步:点击后会进入下面这个代理,首先删除屏幕上的大头针,由于我这里还是需要显示这个房源大头针,这里我做了一个处理保存下来,在for循环中拿到了所有的list中的对象,这些对象就是我们要的周边信息,但是并不是详情,详情是需要拿到这个目标对象UID再次去检索(这里普通检索和详情检索被百度强行分开了,可能处于流量或者模块化的考虑吧)。那么就必须再次创建检索对象了,这次for循环每次都会出现一个详情检索,于是我们可以到详情代理中做事情了。

    //实现PoiSearchDeleage处理回调结果
    - (void)onGetPoiResult:(BMKPoiSearch *)searcher result:(BMKPoiResult *)poiResultList errorCode:(BMKSearchErrorCode)error {
    
        // 清楚屏幕中除却房源外的所有的annotation
        NSMutableArray *array = [NSMutableArray arrayWithArray:self.mapView.annotations];
        //把房源的保存下载
        [array removeObjectAtIndex:0];
        [self.mapView removeAnnotations:array];
        array = [[NSArray arrayWithArray:self.mapView.overlays] mutableCopy];
        [self.mapView removeOverlays:array];
        if (error == BMK_SEARCH_NO_ERROR) {
            for (int i = 0; i < poiResultList.poiInfoList.count; i++) {
                BMKPoiInfo *poi = [poiResultList.poiInfoList objectAtIndex:i];
                //自定义大头针
                BMKPoiDetailSearchOption *option = [[BMKPoiDetailSearchOption alloc] init];
                option.poiUid = poi.uid;
                BMKPoiSearch *se = [[BMKPoiSearch alloc] init];
                se.delegate = self;
                //把所有的POI存入数组,用于最终的释放,避免循环引用;
                [self.poiDetails addObject:se];
                [se poiDetailSearch:option];
            }
        } else if (error == BMK_SEARCH_AMBIGUOUS_KEYWORD){
            NSLog(@"搜索词有歧义");
        } else {
            // 各种情况的判断。。。
        }
    }
    
    

    详情代理,这里我需要不同的大头针图片,做了一个处理

    //周边搜索的详情代理
    - (void)onGetPoiDetailResult:(BMKPoiSearch *)searcher result:(BMKPoiDetailResult *)poiDetailResult errorCode:(BMKSearchErrorCode)errorCode {
        CLLocationCoordinate2D houseCoor;
        houseCoor.latitude = self.latitude;
        houseCoor.longitude = self.longitude;
        
        if (errorCode == BMK_SEARCH_NO_ERROR) {
            YLAnnotationView *item = [[YLAnnotationView alloc] init];
            item.coordinate = poiDetailResult.pt;
            
            switch (self.seletItem) {
                case 1:
                    item.image = [UIImage imageNamed:@"food"];
                    item.subtitle = [NSString stringWithFormat:@"均价:%.2f",poiDetailResult.price];
                    break;
                case 2:
                    item.image = [UIImage imageNamed:@"supermarket"];
                    item.subtitle = poiDetailResult.address;
                    break;
                case 3:
                    item.image = [UIImage imageNamed:@"ATM"];
                    item.subtitle = poiDetailResult.address;
                    break;
                case 4:
                    item.image = [UIImage imageNamed:@"shoping"];
                    item.subtitle = poiDetailResult.address;
                    break;
                default:
                    break;
            }
            item.title = poiDetailResult.name;
            //加个判断,第一次进来的时候设置中心点,不能每次都移动中心,不然POI期间会拖不动地图。
            if (self.isFirst) {
                [self.mapView setCenterCoordinate:houseCoor animated:YES];
            }
            self.isFirst = NO;
            [self.mapView addAnnotation:item];
           
        }else if (errorCode == BMK_SEARCH_AMBIGUOUS_KEYWORD) {
            
            NSLog(@"搜索词有歧义");
    
        }else {
        
        }
    }
    
    
    

    到这里主要代码就结束了。文末我会附上Demo
    二:路径规划
    点击搜索,传过来一种路线方式,并且传来开始地与目的地。我本想直接写出需要注意的地方,但是发现在代码中不少都已经注释了,请大家注意,例如 //每次必须是一个新的对象,不然ptname会混乱
    下面代码有很多逻辑上的处理,为了一体性,我没有删去。

    #pragma mark -- RoutePlanViewDelegate
    //搜路线
    - (void)didSelectorItems:(NSInteger)item withStartName:(NSString *)startName andEndName:(NSString *)endName {
        CLLocationCoordinate2D houseCoor;
        houseCoor.latitude = self.latitude;
        houseCoor.longitude = self.longitude;
        
        //每次必须是一个新的对象,不然pt和name会混乱
        self.startNode = [[BMKPlanNode alloc] init];
        self.endNode = [[BMKPlanNode alloc] init];
        self.startNode.cityName = @"南京";
        self.endNode.cityName = @"南京";
        //设置出发点与终点
        if ([startName isEqualToString:@""] || [endName isEqualToString:@""]) {
            NSLog(@"搜索字段有歧义");
            return;
        }
        if ([startName isEqualToString:@"当前位置"] && [endName isEqualToString:@"房源位置"]) {
            self.startNode.pt = self.userLocation.location.coordinate;
            self.endNode.pt = houseCoor;
        }else if ([endName isEqualToString:@"当前位置"] && [startName isEqualToString:@"房源位置"]) {
            self.startNode.pt = houseCoor;
            self.endNode.pt = self.userLocation.location.coordinate;
        }else if (![startName isEqualToString:@"当前位置"] && [endName isEqualToString:@"房源位置"]) {
            self.startNode.name = startName;
            self.endNode.pt = houseCoor;
        }else if([startName isEqualToString:@"当前位置"] && ![endName isEqualToString:@"房源位置"]) {
            self.startNode.pt = self.userLocation.location.coordinate;
            self.endNode.name = endName;
        }else if(![startName isEqualToString:@"当前位置"] && [endName isEqualToString:@"当前位置"]) {
            self.startNode.name = startName;
            self.endNode.pt = self.userLocation.location.coordinate;
        }else if([startName isEqualToString:@"房源位置"] && ![endName isEqualToString:@"当前位置"]) {
            self.startNode.pt = houseCoor;
            self.endNode.name = endName;
        }else {
            self.startNode.name = startName;
            self.endNode.name = endName;
        }
        NSLog(@"%@ ---- %@",self.startNode.name,self.endNode.name);
    
        if (item == 1) {
            
            //驾车
            BMKDrivingRoutePlanOption *driveRouteSearchOption =[[BMKDrivingRoutePlanOption alloc]init];
            
            driveRouteSearchOption.from = self.startNode;
            
            driveRouteSearchOption.to = self.endNode;
            
            BOOL flag = [self.routeSearch drivingSearch:driveRouteSearchOption];
            if (flag) {
                
            }else {
                
            }
    
        }else if (item == 2) {
            //公交
            BMKMassTransitRoutePlanOption *option = [[BMKMassTransitRoutePlanOption alloc]init];
            option.from = self.startNode;
            option.to = self.endNode;
            BOOL flag = [self.routeSearch massTransitSearch:option];
            
            if(flag) {
                NSLog(@"公交交通检索(支持垮城)发送成功");
            } else {
                NSLog(@"公交交通检索(支持垮城)发送失败");
            }
    
        
        } else if (item == 3) {
            //步行
            BMKWalkingRoutePlanOption *walkingRouteSearchOption = [[BMKWalkingRoutePlanOption alloc] init];
            walkingRouteSearchOption.from = self.startNode;
            walkingRouteSearchOption.to = self.endNode;
            BOOL flag = [self.routeSearch walkingSearch:walkingRouteSearchOption];
            if(flag) {
                NSLog(@"walk检索发送成功");
            }else {
                NSLog(@"walk检索发送失败");
            }
    
        
        }else {
            //骑车
            BMKRidingRoutePlanOption *option = [[BMKRidingRoutePlanOption alloc]init];
            option.from = self.startNode;
            option.to = self.endNode;
            BOOL flag = [self.routeSearch ridingSearch:option];
            if (flag) {
                NSLog(@"骑行规划检索发送成功");
            }else {
                NSLog(@"骑行规划检索发送失败");
            }
    
        }
    }
    
    

    点击后,会进入下面这个代理

    
    #pragma mark -- BMKRouteSearchDelegate
    
    //驾车
    - (void)onGetDrivingRouteResult:(BMKRouteSearch *)searcher result:(BMKDrivingRouteResult *)result errorCode:(BMKSearchErrorCode)error {
    
        NSMutableArray *array = [NSMutableArray arrayWithArray:self.mapView.annotations];
        [array removeObjectAtIndex:0];
        [self.mapView removeAnnotations:array];
        array = [[NSArray arrayWithArray:self.mapView.overlays] mutableCopy];
        [self.mapView removeOverlays:array];
        if (error == BMK_SEARCH_NO_ERROR) {
            //表示一条驾车路线
            BMKDrivingRouteLine *plan = (BMKDrivingRouteLine *)[result.routes objectAtIndex:0];
            // 计算路线方案中的路段数目
            int size = (int)[plan.steps count];
            int planPointCounts = 0;
            for (int i = 0; i < size; i++) {
                //表示驾车路线中的一个路段
                BMKDrivingStep *transitStep = [plan.steps objectAtIndex:i];
                if(i==0){
                    RouteAnnotation *item = [[RouteAnnotation alloc]init];
                    item.coordinate = plan.starting.location;
                    item.title = @"起点";
                    item.type = 0;
                    [self.mapView addAnnotation:item]; // 添加起点标注
                    
                }else if(i==size-1){
                    RouteAnnotation *item = [[RouteAnnotation alloc]init];
                    item.coordinate = plan.terminal.location;
                    item.title = @"终点";
                    item.type = 1;
                    [self.mapView addAnnotation:item]; // 添加终点标注
                }
                //添加annotation节点
                RouteAnnotation *item = [[RouteAnnotation alloc]init];
                item.coordinate = transitStep.entrace.location;
                item.title = transitStep.entraceInstruction;
                item.degree = transitStep.direction  *30;
                item.type = 4;
                [self.mapView addAnnotation:item];
                
                //轨迹点总数累计
                planPointCounts += transitStep.pointsCount;
            }
            // 添加途经点
            if (plan.wayPoints) {
                for (BMKPlanNode *tempNode in plan.wayPoints) {
                    RouteAnnotation *item = [[RouteAnnotation alloc]init];
                    item.coordinate = tempNode.pt;
                    item.type = 5;
                    item.title = tempNode.name;
                    [self.mapView addAnnotation:item];
                }
            }
            //轨迹点
            BMKMapPoint *temppoints = new BMKMapPoint[planPointCounts];
            int i = 0;
            for (int j = 0; j < size; j++) {
                BMKDrivingStep *transitStep = [plan.steps objectAtIndex:j];
                int k=0;
                for(k=0;k<transitStep.pointsCount;k++) {
                    temppoints[i].x = transitStep.points[k].x;
                    temppoints[i].y = transitStep.points[k].y;
                    i++;
                }
                
            }
            // 通过points构建BMKPolyline
            BMKPolyline *polyLine = [BMKPolyline polylineWithPoints:temppoints count:planPointCounts];
            [self.mapView addOverlay:polyLine]; // 添加路线overlay
            delete []temppoints;
            [self mapViewFitPolyLine:polyLine];
        }
    }
    
    
    

    上面我仅仅放了一个驾车的代理,还有步行等没有放上去,太长了,文末为了不想下载代码的同学观看,我会放上整页代码提供参考。
    言归正传,你们发现我有自定义了一个RouteAnnotation类。这个路线需要字段比较多,我不想改动之前大头针类了,就直接重写了一个。如下

    /**
      * 路线的标注  自定义一个大头针类   为了便捷,就直接放这里了
     */
    @interface RouteAnnotation : BMKPointAnnotation {
        int _type; ///<0:起点 1:终点 2:公交 3:地铁 4:驾乘 5:途经点
        int _degree;//旋转的角度
    }
    
    @property (nonatomic) int type;
    @property (nonatomic) int degree;
    @end
    
    @implementation RouteAnnotation
    
    @synthesize type = _type;
    @synthesize degree = _degree;
    @end
    

    如果你也这样做,那么就像我一样在大头针重用方法中做以下判断,并且实现这个方法,如下:

    
     if ([annotation isKindOfClass:[RouteAnnotation class]]) {
            return [self getRouteAnnotationView:view viewForAnnotation:(RouteAnnotation *)annotation];
        }
    #pragma mark -- 获取路线的标注,显示到地图(自定义的一个大头针类实例方法)我只贴到case 0;其他的在文末查找,需要注意的地方我已写注释
    - (BMKAnnotationView *)getRouteAnnotationView:(BMKMapView *)mapview viewForAnnotation:(RouteAnnotation *)routeAnnotation {
        BMKAnnotationView *view = nil;
        //根据大头针类型判断是什么图标
        switch (routeAnnotation.type) {
            case 0:
            {   //开始点
                view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"start_node"];
                if (view == nil) {
                    view = [[BMKAnnotationView alloc] initWithAnnotation:routeAnnotation reuseIdentifier:@"start_node"];
                    //从百度地图资源文件中拿到需要的图片
                    view.image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_nav_start"]];
                    view.centerOffset = CGPointMake(0, -(view.frame.size.height * 0.5));
                    view.canShowCallout = true;
                }
                view.annotation = routeAnnotation;
            }
    
    

    在驾车路线的代理最后我们添加了一条线,就是如下代码

      // 通过points构建BMKPolyline
            BMKPolyline *polyLine = [BMKPolyline polylineWithPoints:temppoints count:planPointCounts];
            [self.mapView addOverlay:polyLine]; // 添加路线overlay
            delete []temppoints;
            [self mapViewFitPolyLine:polyLine];
    
    

    这样我们还需要实现一个划线的代理,这个是必须实现的。还有一个地图路线的范围计算,文末的所有代码中的最后一段,这些都是从百度地图官方代码拿来的。

    #pragma mark -- 路线线条绘制代理
    
    - (BMKOverlayView *)mapView:(BMKMapView *)map viewForOverlay:(id<BMKOverlay>)overlay {
        if ([overlay isKindOfClass:[BMKPolyline class]]) {
            BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithOverlay:overlay];
            //设置线条颜色
            polylineView.fillColor = [[UIColor alloc] initWithRed:0 green:1 blue:1 alpha:1];
            polylineView.strokeColor = [[UIColor alloc] initWithRed:0 green:0 blue:0.8 alpha:0.7];
            polylineView.lineWidth = 3.0;
            return polylineView;
        }
        return nil;
    }
    
    

    虽然上面大多都是复制粘贴把,但是 Demo 代码都是我用心准备的,这里也主要是说个流程。

    三、运行效果

    Untitled,,.gif
    Untitle,.gif

    四、其他补充

    百度地图的集成很简单,按照开发文档几分钟就搞定了,我就不抄写了,但是记录几个可能会出问题的地方吧。

    • Privacy - Location Always Usage Description plist.info请求使用GPS
    • LSApplicationQueriesSchemes 如果你需要调起百度地图客户端
    • Bundle display name plist.info中需要加入,而且是必要的
    • 这个文件用到了c++代码,请务必把文件后缀名改为.mm
      百度地图检索以及路径规划

    代码地址如下:
    http://www.demodashi.com/demo/11030.html

    注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

  • 相关阅读:
    sql 内连接外链接
    深入剖析java并发之阻塞队列LinkedBlockingQueue与ArrayBlockingQueue
    mysql关闭以及重启密码
    学习---书籍
    volatile修饰符
    System.out.println和System.err.println的区别
    懒加载和急加载(lazy/eager)
    load与get在hiberate中的区别
    html
    js
  • 原文地址:https://www.cnblogs.com/demodashi/p/8507655.html
Copyright © 2011-2022 走看看