公交换乘方案的多种表现形式(地图形式和文字展示),同时将BusRouteOverlay开源,帮助您做特殊样式的显示方案。
核心类/接口
类 | 接口 | 说明 | 版本 |
---|---|---|---|
MAMapView | addOverlay: | 向地图窗口添加Overlay。 | V2.0.0版本起 |
addAnnotation: | 向地图窗口添加标注。 | V2.0.0版本起 | |
MAMapViewDelegate | mapView:viewForAnnotation: | 地图上的起始点,终点,拐点的标注的回调,可以自定义图标展示等。 | V2.0.0版本起 |
mapView:rendererForOverlay: | 地图上覆盖物的渲染的回调,可以设置路径线路的宽度,颜色等。 | V3.0.0版本起 | |
AMapSearchAPI | AMapTransitRouteSearch: | 公交路径规划查询接口。 | V3.0.0版本起 |
AMapTransitRouteSearchRequest | city | 查询城市。 | V3.0.0版本起 |
requireExtension | 是否返回扩展信息,默认NO。 | V3.0.0版本起 | |
AMapRouteSearchBaseRequest | origin | 出发点坐标。 | V3.0.0版本起 |
destination | 目的地坐标。 | V3.0.0版本起 | |
AMapSearchDelegate | onRouteSearchDone:response: | 路径规划查询完成回调。 | V3.0.0版本起 |
1、如何解析公交换乘结果对象。
a)通过response.route.transits 可以获取到 AMapTransit 列表。
b)AMapTransit 对象就是一个完整的公交换乘方案,每个方案都是由多个 AMapSegment 构成。
c)AMapSegment 对象由 AMapWalking(步行)和 AMapBusLine(公交线路)构成。
在本示例中,MANaviRoute 是一个生成路线 Polyline 和起终点以及中间节点的 Annotaion 的工具类,省去了您去解析 response 对象的成本。
- (void)presentCurrentRouteCourse {
if (self.routeArray.count <= 0) {
return;
}
[self.naviRoute removeFromMapView]; //清空地图上已有的路线
AMapGeoPoint *startPoint = [AMapGeoPoint locationWithLatitude:self.startAnnotation.coordinate.latitude longitude:self.startAnnotation.coordinate.longitude]; //起点
AMapGeoPoint *endPoint = [AMapGeoPoint locationWithLatitude:self.destinationAnnotation.coordinate.latitude longitude:self.destinationAnnotation.coordinate.longitude]; //终点
//根据已经规划的换乘方案,起点,终点,生成显示方案
self.naviRoute = [MANaviRoute naviRouteForTransit:self.route.transits[self.currentRouteIndex] startPoint:startPoint endPoint:endPoint];
[self.naviRoute addToMapView:self.mapView]; //显示到地图上
UIEdgeInsets edgePaddingRect = UIEdgeInsetsMake(RoutePlanningPaddingEdge, RoutePlanningPaddingEdge, RoutePlanningPaddingEdge, RoutePlanningPaddingEdge);
//缩放地图使其适应polylines的展示
[self.mapView setVisibleMapRect:[CommonUtility mapRectForOverlays:self.naviRoute.routePolylines] edgePadding:edgePaddingRect animated:YES];
}
//在地图上显示当前选择的路径
func presentCurrentRouteCourse() {
if self.routeArray.count <= 0 {
return
}
self.naviRoute?.removeFromMapView() //清空地图上已有的路线
let startPoint = AMapGeoPoint.location(withLatitude: CGFloat(self.startAnnotation.coordinate.latitude), longitude: CGFloat(self.startAnnotation.coordinate.longitude)) //起点
let endPoint = AMapGeoPoint.location(withLatitude: CGFloat(self.destinationAnnotation.coordinate.latitude), longitude: CGFloat(self.destinationAnnotation.coordinate.longitude)) //终点
//根据已经规划的路径,起点,终点,规划类型,是否显示实时路况,生成显示方案
self.naviRoute = MANaviRoute(for: self.route.transits[self.currentRouteIndex], start: startPoint, end: endPoint)
self.naviRoute?.add(to: self.mapView)
//显示到地图上
let edgePaddingRect = UIEdgeInsetsMake(RoutePlanningPaddingEdge, RoutePlanningPaddingEdge, RoutePlanningPaddingEdge, RoutePlanningPaddingEdge)
//缩放地图使其适应polylines的展示
self.mapView.setVisibleMapRect(CommonUtility.mapRect(forOverlays: self.naviRoute?.routePolylines), edgePadding: edgePaddingRect, animated: true)
}
2、如何更改显示在地图上的路线的的样式(包括:出发点和目的地的图标、路线的颜色、宽度等等)。
//地图上覆盖物的渲染,可以设置路径线路的宽度,颜色等
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id<MAOverlay>)overlay {
//虚线,如需要步行的
if ([overlay isKindOfClass:[LineDashPolyline class]]) {
MAPolylineRenderer *polylineRenderer = [[MAPolylineRenderer alloc] initWithPolyline:((LineDashPolyline *)overlay).polyline];
polylineRenderer.lineWidth = 6;
polylineRenderer.lineDash = YES;
polylineRenderer.strokeColor = [UIColor redColor];
return polylineRenderer;
}
//路径为单一颜色,比如公交线路目前为blueColor
if ([overlay isKindOfClass:[MANaviPolyline class]]) {
MANaviPolyline *naviPolyline = (MANaviPolyline *)overlay;
MAPolylineRenderer *polylineRenderer = [[MAPolylineRenderer alloc] initWithPolyline:naviPolyline.polyline];
polylineRenderer.lineWidth = 6;
if (naviPolyline.type == MANaviAnnotationTypeWalking){
polylineRenderer.strokeColor = self.naviRoute.walkingColor;
}else if (naviPolyline.type == MANaviAnnotationTypeRailway){
polylineRenderer.strokeColor = self.naviRoute.railwayColor;
}else{
polylineRenderer.strokeColor = self.naviRoute.routeColor;
}
return polylineRenderer;
}
//showTraffic为YES时,需要带实时路况,路径为多颜色渐变,多用于驾车路线规划,公交路线规划为单一颜色
if ([overlay isKindOfClass:[MAMultiPolyline class]]) {
MAMultiColoredPolylineRenderer * polylineRenderer = [[MAMultiColoredPolylineRenderer alloc] initWithMultiPolyline:overlay];
polylineRenderer.lineWidth = 6;
polylineRenderer.strokeColors = [self.naviRoute.multiPolylineColors copy];
return polylineRenderer;
}
return nil;
}
//地图上的起始点,终点,拐点的标注,可以自定义图标展示等
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation {
if ([annotation isKindOfClass:[MAPointAnnotation class]]) {
//标注的view的初始化和复用
static NSString *routePlanningCellIdentifier = @"RoutePlanningCellIdentifier";
MAAnnotationView *poiAnnotationView = (MAAnnotationView*)[self.mapView dequeueReusableAnnotationViewWithIdentifier:routePlanningCellIdentifier];
if (poiAnnotationView == nil) {
poiAnnotationView = [[MAAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:routePlanningCellIdentifier];
}
poiAnnotationView.canShowCallout = YES;
poiAnnotationView.image = nil;
//拐点的图标标注
if ([annotation isKindOfClass:[MANaviAnnotation class]]) {
switch (((MANaviAnnotation*)annotation).type) {
case MANaviAnnotationTypeRailway:
poiAnnotationView.image = [UIImage imageNamed:@"railway_station"];
break;
case MANaviAnnotationTypeBus:
poiAnnotationView.image = [UIImage imageNamed:@"bus"];
break;
case MANaviAnnotationTypeDrive:
poiAnnotationView.image = [UIImage imageNamed:@"car"];
break;
case MANaviAnnotationTypeWalking:
poiAnnotationView.image = [UIImage imageNamed:@"man"];
break;
default:
break;
}
}else{
//起点,终点的图标标注
if ([[annotation title] isEqualToString:(NSString*)RoutePlanningViewControllerStartTitle]) {
poiAnnotationView.image = [UIImage imageNamed:@"startPoint"]; //起点
} else if ([[annotation title] isEqualToString:(NSString*)RoutePlanningViewControllerDestinationTitle]) {
poiAnnotationView.image = [UIImage imageNamed:@"endPoint"]; //终点
}
}
return poiAnnotationView;
}
return nil;
}
func mapView(_ mapView: MAMapView!, rendererFor overlay: MAOverlay!) -> MAOverlayRenderer! {
//虚线,如需要步行的
if overlay.isKind(of: LineDashPolyline.self) {
let naviPolyline: LineDashPolyline = overlay as! LineDashPolyline
let renderer: MAPolylineRenderer = MAPolylineRenderer(overlay: naviPolyline.polyline)
renderer.lineWidth = 6
renderer.strokeColor = UIColor.red
renderer.lineDash = true
return renderer
}
//showTraffic为NO时,不需要带实时路况,路径为单一颜色,比如步行线路目前为海蓝色
if overlay.isKind(of: MANaviPolyline.self) {
let naviPolyline: MANaviPolyline = overlay as! MANaviPolyline
let renderer: MAPolylineRenderer = MAPolylineRenderer(overlay: naviPolyline.polyline)
renderer.lineWidth = 6
if naviPolyline.type == MANaviAnnotationType.walking {
renderer.strokeColor = naviRoute?.walkingColor
}
else if naviPolyline.type == MANaviAnnotationType.railway {
renderer.strokeColor = naviRoute?.railwayColor;
}
else {
renderer.strokeColor = naviRoute?.routeColor;
}
return renderer
}
//showTraffic为YES时,需要带实时路况,路径为多颜色渐变
if overlay.isKind(of: MAMultiPolyline.self) {
let renderer: MAMultiColoredPolylineRenderer = MAMultiColoredPolylineRenderer(multiPolyline: overlay as! MAMultiPolyline!)
renderer.lineWidth = 6
renderer.strokeColors = naviRoute?.multiPolylineColors
return renderer
}
return nil
}
func mapView(_ mapView: MAMapView!, viewFor annotation: MAAnnotation!) -> MAAnnotationView! {
if annotation.isKind(of: MAPointAnnotation.self) {
//标注的view的初始化和复用
let pointReuseIndetifier = "RoutePlanningCellIdentifier"
var annotationView: MAAnnotationView? = mapView.dequeueReusableAnnotationView(withIdentifier: pointReuseIndetifier)
if annotationView == nil {
annotationView = MAAnnotationView(annotation: annotation, reuseIdentifier: pointReuseIndetifier)
annotationView!.canShowCallout = true
annotationView!.isDraggable = false
}
annotationView!.image = nil
if annotation.isKind(of: MANaviAnnotation.self) {
let naviAnno = annotation as! MANaviAnnotation
switch naviAnno.type {
case MANaviAnnotationType.railway:
annotationView!.image = UIImage(named: "railway_station")
break
case MANaviAnnotationType.drive:
annotationView!.image = UIImage(named: "car")
break
case MANaviAnnotationType.riding:
annotationView!.image = UIImage(named: "ride")
break
case MANaviAnnotationType.walking:
annotationView!.image = UIImage(named: "man")
break
case MANaviAnnotationType.bus:
annotationView!.image = UIImage(named: "bus")
break
}
}
else {
if annotation.title == "起点" {
annotationView!.image = UIImage(named: "startPoint")
}
else if annotation.title == "终点" {
annotationView!.image = UIImage(named: "endPoint")
}
}
return annotationView!
}
return nil
}
3、如何以列表的形式显示公交详情。
//根据transit的具体字段,显示信息
- (void)setUpViewsWithData {
NSInteger hours = self.transit.duration / 3600;
NSInteger minutes = (NSInteger)(self.transit.duration / 60) % 60;
self.timeInfoLabel.text = [NSString stringWithFormat:@"%u小时%u分钟(%u公里)",(unsigned)hours,(unsigned)minutes,(unsigned)self.transit.distance / 1000];
self.taxiCostInfoLabel.text = [NSString stringWithFormat:@"打车约%.0f元",self.route.taxiCost];
self.routeDetailDataArray = @[].mutableCopy;
[self.routeDetailDataArray addObject:@{RoutePathDetailStepInfoImageName : @"start",RoutePathDetailStepInfoText : @"开始出发"}]; // 图片的名字,具体步骤的文字信息
for (AMapSegment *segment in self.transit.segments) {
AMapRailway *railway = segment.railway; //火车
AMapBusLine *busline = [segment.buslines firstObject]; // 地铁或者公交线路
AMapWalking *walking = segment.walking; //搭乘地铁或者公交前的步行信息
if (walking.distance) {
NSString *walkInfo = [NSString stringWithFormat:@"步行%u米",(unsigned)walking.distance];
[self.routeDetailDataArray addObject:@{RoutePathDetailStepInfoImageName : @"walkRoute",RoutePathDetailStepInfoText : walkInfo}];
}
if (busline.name) {
NSString *busImageName = @"busRoute";
if ([busline.type isEqualToString:@"地铁线路"]) { //区分公交和地铁
busImageName = @"underGround";
}
//viaBusStops途径的公交车站的数组,如需具体站名,可解析。
NSString *busInfoText = [NSString stringWithFormat:@"乘坐%@,在 %@ 上车,途经 %u 站,在 %@ 下车",busline.name,busline.departureStop.name,(unsigned)(busline.viaBusStops.count + 1),busline.arrivalStop.name];
[self.routeDetailDataArray addObject:@{RoutePathDetailStepInfoImageName : busImageName,RoutePathDetailStepInfoText : busInfoText}];
} else if (railway.uid) {
[self.routeDetailDataArray addObject:@{RoutePathDetailStepInfoImageName : @"railwayRoute",RoutePathDetailStepInfoText : railway.name}];
}
}
[self.routeDetailDataArray addObject:@{RoutePathDetailStepInfoImageName : @"end",RoutePathDetailStepInfoText : @"抵达终点"}];
}
//根据transit的具体字段,显示信息
func setUpViewsWithData() {
let hours = self.transit!.duration / 3600
let minutes = Int(self.transit!.duration / 60) % 60
self.timeInfoLabel.text = "\(UInt(hours))小时\(UInt(minutes))分钟(\(UInt(self.transit!.distance) / 1000)公里)"
self.taxiCostInfoLabel.text = String(format: "打车约%.0f元", self.route.taxiCost)
self.routeDetailDataArray = []
self.routeDetailDataArray.add([RoutePathDetailStepInfoImageName : "start", RoutePathDetailStepInfoText : "开始出发"])
for segment: AMapSegment in self.transit.segments as Array {
if segment.walking != nil {
let walkInfo = "步行\(segment.walking.distance)米"
self.routeDetailDataArray.add([RoutePathDetailStepInfoImageName : "walkRoute", RoutePathDetailStepInfoText : walkInfo])
}
if (segment.buslines.first?.name != nil) {
let busline: AMapBusLine = segment.buslines.first!
var busImageName = "busRoute"
if busline.type == "地铁线路" { //区分公交和地铁
busImageName = "underGround"
}
//viaBusStops途径的公交车站的数组,如需具体站名,可解析。
let busInfoText = String(format: "乘坐%@,在 %@ 上车,途经 %u 站,在 %@ 下车", busline.name,busline.departureStop.name,busline.viaBusStops.count + 1,busline.arrivalStop.name)
self.routeDetailDataArray.add([RoutePathDetailStepInfoImageName : busImageName, RoutePathDetailStepInfoText : busInfoText])
} else if segment.railway.uid != nil {
self.routeDetailDataArray.add([RoutePathDetailStepInfoImageName : "railwayRoute", RoutePathDetailStepInfoText : segment.railway.name])
}
}
self.routeDetailDataArray.add([RoutePathDetailStepInfoImageName : "end", RoutePathDetailStepInfoText : "抵达终点"])
}
公交换乘方案的多种表现形式(地图形式和列表展示),同时将 BusRouteOverlay 开源,帮助您做特殊样式的显示方案。
核心类/接口
类 | 接口 | 说明 | 版本 |
---|---|---|---|
RouteSearch.BusRouteQuery | BusRouteQuery(RouteSearch.FromAndTo fromAndTo, int mode, java.lang.String city, int nightFlag) | 构造函数,构造公交路线规划查询参数对象。 | V2.1.0版本起 |
RouteSearch | calculateBusRouteAsyn(RouteSearch.BusRouteQuery busQuery) | 公交路线规划异步接口。 | V2.1.0版本起 |
RouteSearch.OnRouteSearchListener | onBusRouteSearched(BusRouteResult busRouteResult, int errorCode) | 公交换乘路径规划结果的回调方法。 | V2.1.0版本起 |
BusRouteResult | getPaths() | 返回公交路径规划方案。 | V2.1.0版本起 |
BusPath | getSteps() | 返回公交路径规划方案的路段列表。 | V2.1.0版本起 |
BusStep | getBusLines() | 返回此路段的公交导航信息。 | V2.1.0版本起 |
getWalk() | 返回此路段的步行信息。 | V2.1.0版本起 |
1、如何解析公交换乘结果对象?
a)通过 BusRouteResult.getPaths() 方法获取全部的公交换成方案的列表,列表中是 BusPath 对象。
b)BusPath 对象就是一个完整的公交换乘方案,每个方案都是由多个 BusStep 构成。
c)BusStep 对象由 RouteBusWalkItem(步行导航信息)和 RouteBusLineItem(公交导航信息)构成。
2、如何更改显示在地图上的 BusRouteOverlay 的样式(如:起终点图标、线路的颜色、宽度等)?
在本示例中,BusRouteOverlay 已对所有开发者开源,您可以参考源码修改 Overlay 的样式,其中: