iOS-百度地图自定义气泡

CarWingfiel 7年前
   <p style="text-align:center"><img src="https://simg.open-open.com/show/e8537c1d4ae6485eebd57bdcd8e4fac5.png"></p>    <p style="text-align:center">Paste_Image.png</p>    <p>文章简单实现百度地图添加标注和自定义气泡的功能,基本都是SDK 提供的方法,不做详细解释。</p>    <p>很久没有更新,具体教程请以官网文档为准,本文只提供设计思路。</p>    <p>1.添加多个标注和自定义气泡</p>    <ul>     <li>添加自定义标注</li>    </ul>    <pre>  <code class="language-objectivec">[_mapView addAnnotations:array];</code></pre>    <ul>     <li>实现代理方法</li>    </ul>    <pre>  <code class="language-objectivec">#pragma mark -- BMKMapdelegate    /**   *根据anntation生成对应的View   *@param mapView 地图View   *@param annotation 指定的标注   *@return 生成的标注View   */  -(BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id <BMKAnnotation>)annotation  {      if ([annotation isKindOfClass:[BMKPointAnnotation class]]) {          BMKPinAnnotationView *newAnnotationView = [[BMKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:@"myAnnotation"];          newAnnotationView.animatesDrop = YES;          newAnnotationView.annotation = annotation;          //这里我根据自己需要,继承了BMKPointAnnotation,添加了标注的类型等需要的信息          MyBMKPointAnnotation *tt = (MyBMKPointAnnotation *)annotation;            //判断类别,需要添加不同类别,来赋予不同的标注图片          if (tt.profNumber == 100000) {              newAnnotationView.image = [UIImage imageNamed:@"ic_map_mode_category_merchants_normal.png"];          }else if (tt.profNumber == 100001){            }          //设定popView的高度,根据是否含有缩略图          double popViewH = 60;          if (annotation.subtitle == nil) {              popViewH = 38;          }          UIView *popView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, ScreenWidth-100, popViewH)];          popView.backgroundColor = [UIColor whiteColor];          [popView.layer setMasksToBounds:YES];          [popView.layer setCornerRadius:3.0];          popView.alpha = 0.9;            //自定义气泡的内容,添加子控件在popView上          UILabel *driverName = [[UILabel alloc]initWithFrame:CGRectMake(8, 4, 160, 30)];          driverName.text = annotation.title;          driverName.numberOfLines = 0;          driverName.backgroundColor = [UIColor clearColor];          driverName.font = [UIFont systemFontOfSize:15];          driverName.textColor = [UIColor blackColor];          driverName.textAlignment = NSTextAlignmentLeft;          [popView addSubview:driverName];            UILabel *carName = [[UILabel alloc]initWithFrame:CGRectMake(8, 30, 180, 30)];          carName.text = annotation.subtitle;          carName.backgroundColor = [UIColor clearColor];          carName.font = [UIFont systemFontOfSize:11];          carName.textColor = [UIColor lightGrayColor];          carName.textAlignment = NSTextAlignmentLeft;          [popView addSubview:carName];            if (annotation.subtitle != nil) {          UIButton *searchBn = [[UIButton alloc]initWithFrame:CGRectMake(170, 0, 50, 60)];          [searchBn setTitle:@"查看路线" forState:UIControlStateNormal];          searchBn.backgroundColor = mainColor;              searchBn.titleLabel.numberOfLines = 0;          [searchBn addTarget:self action:@selector(searchLine)];          [popView addSubview:searchBn];          }            BMKActionPaopaoView *pView = [[BMKActionPaopaoView alloc]initWithCustomView:popView];          pView.frame = CGRectMake(0, 0, ScreenWidth-100, popViewH);          ((BMKPinAnnotationView*)newAnnotationView).paopaoView = nil;          ((BMKPinAnnotationView*)newAnnotationView).paopaoView = pView;          return newAnnotationView;      }      return nil;  }</code></pre>    <ul>     <li>实现点击标注和气泡协议</li>    </ul>    <pre>  <code class="language-objectivec">/**   * 当选中一个annotation views时,调用此接口   * @param mapView 地图View   * @param views 选中的annotation views   */  - (void)mapView:(BMKMapView *)mapView didSelectAnnotationView:(BMKAnnotationView *)view  {      _shopCoor = view.annotation.coordinate;  }  /**   *  选中气泡调用方法   *  @param mapView 地图   *  @param view    annotation   */  - (void)mapView:(BMKMapView *)mapView annotationViewForBubble:(BMKAnnotationView *)view  {      MyBMKPointAnnotation *tt = (MyBMKPointAnnotation *)view.annotation;      if (tt.shopID) {          BusinessIfonUVC *BusinessIfonVC = [[BusinessIfonUVC alloc]init];          BusinessIfonVC.shopId = tt.shopID;          [self.navigationController pushViewController:BusinessIfonVC animated:YES];      }  }</code></pre>    <p>2.实现路线搜索,路径规划,获取街道名称等功能</p>    <ul>     <li>通过经纬度获取地址,逆地理编码</li>    </ul>    <pre>  <code class="language-objectivec">-(void)getStartAddress  {      //起点地址      CLGeocoder *Geocoder = [[CLGeocoder alloc]init];      CLGeocodeCompletionHandler handler = ^(NSArray *place,NSError *error){          for(CLPlacemark *placemark in place){              NSString *tmp = [[NSString alloc]init];              tmp = placemark.subThoroughfare;              if (tmp == nil) {                  tmp = @"";              }              NSString *startAdr = [[NSString alloc]initWithFormat:@"%@%@",placemark.thoroughfare,tmp];              _startCityText.text = placemark.locality;              if ([startAdr isEqualToString:@"(null)"]) {                  _startAddrText.text = @"获取地址失败";              }else{              _startAddrText.text = startAdr;              }      }      };      CLLocation *loc = [[CLLocation alloc]initWithLatitude:self.startCoor.latitude longitude:self.startCoor.longitude];      [Geocoder reverseGeocodeLocation:loc completionHandler:handler];    }</code></pre>    <ul>     <li>路径检索</li>    </ul>    <pre>  <code class="language-objectivec">- (void)onGetTransitRouteResult:(BMKRouteSearch*)searcher result:(BMKTransitRouteResult*)result errorCode:(BMKSearchErrorCode)error  {      NSMutableArray *lineArr = [[NSMutableArray alloc]init];        NSArray* array = [NSArray arrayWithArray:_mapView.annotations];      [_mapView removeAnnotations:array];      array = [NSArray arrayWithArray:_mapView.overlays];      [_mapView removeOverlays:array];      if (error == BMK_SEARCH_NO_ERROR) {          for(int j = 0; j < [result.routes count];j++)          {            NSMutableArray *busTitleArr = [[NSMutableArray alloc]init];          NSMutableArray *lineStepsArr = [[NSMutableArray alloc]init];          NSMutableArray *stepsArr = [[NSMutableArray alloc]init];      //生成数据模型          LineInfoModel *lineInfo = [[LineInfoModel alloc]init];          BMKTransitRouteLine* plan = (BMKTransitRouteLine*)[result.routes objectAtIndex:j];      //数据模型:获得路线长度          lineInfo.distance = plan.distance;      //数据模型:获得路线消耗时间          lineInfo.dates = plan.duration.dates;          lineInfo.hours = plan.duration.hours;          lineInfo.minutes = plan.duration.minutes;          lineInfo.seconds = plan.duration.seconds;      // 获得轨迹点          lineInfo.planStepsArr = plan.steps;          // 计算路线方案中的路段数目          int size = [plan.steps count];          int planPointCounts = 0;            for (int i = 0; i < size; i++) {              BMKTransitStep* transitStep = [plan.steps objectAtIndex:i];        //数据模型:获得乘坐公交数组              DLog(@"%@",transitStep.vehicleInfo.title);              if (transitStep.vehicleInfo.title) {                  [busTitleArr addObject:transitStep.vehicleInfo.title];              }      //数据模型:获取换乘信息              if (transitStep.instruction) {                  transitStep.instruction = [transitStep.instruction stringByReplacingOccurrencesOfString:@"<font color=\"#313233\">" withString:@""];                  [lineStepsArr addObject:transitStep.instruction];              }              DLog(@"%@ %@",transitStep.vehicleInfo.title,transitStep.instruction);                if(i==0){                  RouteAnnotation* item = [[RouteAnnotation alloc]init];                  item.coordinate = plan.starting.location;                  item.title = @"起点";                  item.type = 0;  //                [_mapView addAnnotation:item]; // 添加起点标注  //       //                  [stepsArr addObject:item];              }else if(i==size-1){                  RouteAnnotation* item = [[RouteAnnotation alloc]init];                  item.coordinate = plan.terminal.location;                  item.title = @"终点";                  item.type = 1;                  [stepsArr addObject:item];  //                [_mapView addAnnotation:item]; // 添加起点标注  //                        }              RouteAnnotation* item = [[RouteAnnotation alloc]init];              item.coordinate = transitStep.entrace.location;              item.title = transitStep.instruction;              transitStep.instruction = [transitStep.instruction stringByReplacingOccurrencesOfString:@"<font color=\"#313233\">" withString:@""];                item.type = 3;              [stepsArr addObject:item];  //            [_mapView addAnnotation:item];  //   //              //            //轨迹点总数累计              planPointCounts += transitStep.pointsCount;          }          lineInfo.vehicleInfoArr = busTitleArr;          lineInfo.lineStepsArr = lineStepsArr;          lineInfo.stepsArr = stepsArr;          lineInfo.planPointCounts = planPointCounts;            [lineArr addObject:lineInfo];    //        //轨迹点  //        BMKMapPoint * temppoints = new BMKMapPoint[planPointCounts];  //        int i = 0;  //        for (int j = 0; j < size; j++) {  //            BMKTransitStep* 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++;  //            }            }          self.lineStatusArr = lineArr;        // 通过points构建BMKPolyline  //      BMKPolyline* polyLine = [BMKPolyline polylineWithPoints:temppoints count:planPointCounts];  //      [_mapView addOverlay:polyLine]; // 添加路线overlay  //      delete []temppoints;  //        }          [_tableView reloadData];        }    }  - (void)onGetDrivingRouteResult:(BMKRouteSearch*)searcher result:(BMKDrivingRouteResult*)result errorCode:(BMKSearchErrorCode)error  {      NSArray* array = [NSArray arrayWithArray:_mapView.annotations];      [_mapView removeAnnotations:array];      array = [NSArray arrayWithArray:_mapView.overlays];      [_mapView removeOverlays:array];      if (error == BMK_SEARCH_NO_ERROR) {          BMKDrivingRouteLine* plan = (BMKDrivingRouteLine*)[result.routes objectAtIndex:0];          // 计算路线方案中的路段数目          int size = [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;                  [_mapView addAnnotation:item]; // 添加起点标注                  }else if(i==size-1){                  RouteAnnotation* item = [[RouteAnnotation alloc]init];                  item.coordinate = plan.terminal.location;                  item.title = @"终点";                  item.type = 1;                  [_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;              [_mapView addAnnotation:item];                //轨迹点总数累计              planPointCounts += transitStep.pointsCount;          }          // 添加途经点          if (plan.wayPoints) {              for (BMKPlanNode* tempNode in plan.wayPoints) {                  RouteAnnotation* item = [[RouteAnnotation alloc]init];                  item = [[RouteAnnotation alloc]init];                  item.coordinate = tempNode.pt;                  item.type = 5;                  item.title = tempNode.name;                  [_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];          [_mapView addOverlay:polyLine]; // 添加路线overlay          delete []temppoints;          }  }    - (void)onGetWalkingRouteResult:(BMKRouteSearch*)searcher result:(BMKWalkingRouteResult*)result errorCode:(BMKSearchErrorCode)error  {      NSArray* array = [NSArray arrayWithArray:_mapView.annotations];      [_mapView removeAnnotations:array];      array = [NSArray arrayWithArray:_mapView.overlays];      [_mapView removeOverlays:array];      if (error == BMK_SEARCH_NO_ERROR) {          BMKWalkingRouteLine* plan = (BMKWalkingRouteLine*)[result.routes objectAtIndex:0];          int size = [plan.steps count];          int planPointCounts = 0;          for (int i = 0; i < size; i++) {              BMKWalkingStep* transitStep = [plan.steps objectAtIndex:i];              if(i==0){                  RouteAnnotation* item = [[RouteAnnotation alloc]init];                  item.coordinate = plan.starting.location;                  item.title = @"起点";                  item.type = 0;                  [_mapView addAnnotation:item]; // 添加起点标注                  }else if(i==size-1){                  RouteAnnotation* item = [[RouteAnnotation alloc]init];                  item.coordinate = plan.terminal.location;                  item.title = @"终点";                  item.type = 1;                  [_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;              [_mapView addAnnotation:item];                //轨迹点总数累计              planPointCounts += transitStep.pointsCount;          }            //轨迹点          BMKMapPoint * temppoints = new BMKMapPoint[planPointCounts];          int i = 0;          for (int j = 0; j < size; j++) {              BMKWalkingStep* 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];          [_mapView addOverlay:polyLine]; // 添加路线overlay          delete []temppoints;        }    }</code></pre>    <p>3.路径规划</p>    <p>我这里实现是跳转到另一个控制器中了,下面是他一些需要的数据</p>    <pre>  <code class="language-objectivec">//路线长度  @property (nonatomic,assign) int distance;  //路线消耗时间  @property (nonatomic,assign) int dates;  @property (nonatomic,assign) int hours;  @property (nonatomic,assign) int minutes;  @property (nonatomic,assign) int seconds;  //交通工具数组  @property (nonatomic,strong) NSArray *vehicleInfoArr;  //换乘信息  @property (nonatomic,strong) NSArray *lineStepsArr;  //节点  @property (nonatomic,strong) NSArray *stepsArr;  //轨迹点个数  @property (nonatomic,assign) int planPointCounts;  //轨迹点  @property (nonatomic,strong) NSArray *planStepsArr;</code></pre>    <p>接下来是画路经,关于乘车数据的展示,就是一个tableview上添加了手势</p>    <pre>  <code class="language-objectivec">-(void)drawMap  {      BMKPointAnnotation* item = [[BMKPointAnnotation alloc]init];      item = [_lineInfo.stepsArr firstObject];      [_mapView setCenterCoordinate:item.coordinate];      [_mapView addAnnotations:_lineInfo.stepsArr];        BMKMapPoint* temppoints = (BMKMapPoint *)malloc(sizeof(CLLocationCoordinate2D) * _lineInfo.planPointCounts);      int i = 0;      for (int j = 0; j < [_lineInfo.planStepsArr count]; j++) {              BMKTransitStep* transitStep = [_lineInfo.planStepsArr 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++;            }        }        BMKPolyline* polyLine =[BMKPolyline  polylineWithPoints:temppoints count:_lineInfo.planPointCounts];      if (nil != polyLine) {             [_mapView addOverlay:polyLine]; // 添加路线overlay      }      free(temppoints);  }    - (BMKOverlayView*)mapView:(BMKMapView *)map viewForOverlay:(id<BMKOverlay>)overlay  {      if ([overlay isKindOfClass:[BMKPolyline class]]) {          BMKPolylineView* polylineView = [[BMKPolylineView alloc] initWithOverlay:overlay];          polylineView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:1];          polylineView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];          polylineView.lineWidth = 3.0;          return polylineView;      }      return nil;  }</code></pre>    <pre>  <code class="language-objectivec">// 判断标注类型,来处理  - (BMKAnnotationView*)getRouteAnnotationView:(BMKMapView *)mapview viewForAnnotation:(MyBMKPointAnnotation*)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.png"]];                  view.centerOffset = CGPointMake(0, -(view.frame.size.height * 0.5));                  view.canShowCallout = TRUE;              }              view.annotation = routeAnnotation;          }              break;          case 1:          {              view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"end_node"];              if (view == nil) {                  view = [[BMKAnnotationView alloc]initWithAnnotation:routeAnnotation reuseIdentifier:@"end_node"];                  view.image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_nav_end.png"]];                  view.centerOffset = CGPointMake(0, -(view.frame.size.height * 0.5));                  view.canShowCallout = TRUE;              }              view.annotation = routeAnnotation;          }              break;          case 2:          {              view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"bus_node"];              if (view == nil) {                  view = [[BMKAnnotationView alloc]initWithAnnotation:routeAnnotation reuseIdentifier:@"bus_node"];                  view.image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_nav_bus.png"]];                  view.canShowCallout = TRUE;              }              view.annotation = routeAnnotation;          }              break;          case 3:          {              view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"rail_node"];              if (view == nil) {                  view = [[BMKAnnotationView alloc]initWithAnnotation:routeAnnotation reuseIdentifier:@"rail_node"];                  view.image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_nav_rail.png"]];                  view.canShowCallout = TRUE;              }              view.annotation = routeAnnotation;          }              break;          case 4:          {              view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"route_node"];              if (view == nil) {                  view = [[BMKAnnotationView alloc]initWithAnnotation:routeAnnotation reuseIdentifier:@"route_node"];                  view.canShowCallout = TRUE;              } else {                  [view setNeedsDisplay];              }                UIImage* image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_direction.png"]];              view.image = [image imageRotatedByDegrees:routeAnnotation.degree];              view.annotation = routeAnnotation;            }              break;          case 5:          {              view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"waypoint_node"];              if (view == nil) {                  view = [[BMKAnnotationView alloc]initWithAnnotation:routeAnnotation reuseIdentifier:@"waypoint_node"];                  view.canShowCallout = TRUE;              } else {                  [view setNeedsDisplay];              }                UIImage* image = [UIImage imageWithContentsOfFile:[self getMyBundlePath1:@"images/icon_nav_waypoint.png"]];              view.image = [image imageRotatedByDegrees:routeAnnotation.degree];              view.annotation = routeAnnotation;          }              break;          default:              break;      }        return view;  }    - (BMKAnnotationView *)mapView:(BMKMapView *)view viewForAnnotation:(id <BMKAnnotation>)annotation  {      if ([annotation isKindOfClass:[BMKPointAnnotation class]]) {          return [self getRouteAnnotationView:view viewForAnnotation:(MyBMKPointAnnotation *)annotation];      }      return nil;  }    - (UIImage*)imageRotatedByDegrees:(CGFloat)degrees  {        CGFloat width = CGImageGetWidth(self.CGImage);      CGFloat height = CGImageGetHeight(self.CGImage);        CGSize rotatedSize;        rotatedSize.width = width;      rotatedSize.height = height;        UIGraphicsBeginImageContext(rotatedSize);      CGContextRef bitmap = UIGraphicsGetCurrentContext();      CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);      CGContextRotateCTM(bitmap, degrees * M_PI / 180);      CGContextRotateCTM(bitmap, M_PI);      CGContextScaleCTM(bitmap, -1.0, 1.0);      CGContextDrawImage(bitmap, CGRectMake(-rotatedSize.width/2, -rotatedSize.height/2, rotatedSize.width, rotatedSize.height), self.CGImage);      UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();      UIGraphicsEndImageContext();      return newImage;  }</code></pre>    <p>MarkDown不会用,代码弄得很乱,但是经过几天的研究,可以很舒服的上代码了!</p>    <p> </p>    <p>来自:http://www.jianshu.com/p/6a334f071c69</p>    <p> </p>