当我初始化地图时,它会显示我的位置和目的地(根据字符串进行正向地理编码),但不会在它们之间绘制方向。
这是我的代码:
#import "EventDetailMapViewController.h"
@interface EventDetailMapViewController ()
@property (nonatomic,strong) MKMapItem *destination;
@end
@implementation EventDetailMapViewController
CLPlacemark *thePlacemark;
MKRoute *routeDetails;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_mapView.showsUserLocation = YES;
self.navigationController.toolbarHidden = NO;
_mapView.delegate = self;
[self getRoute];
}
- (void)addAnnotation:(CLPlacemark *)placemark {
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = CLLocationCoordinate2DMake(placemark.location.coordinate.latitude, placemark.location.coordinate.longitude);
point.title = [placemark.addressDictionary objectForKey:@"Street"];
point.subtitle = [placemark.addressDictionary objectForKey:@"City"];
[self.mapView addAnnotation:point];
}
-(void)showRoute:(MKDirectionsResponse *)response{
for (MKRoute *route in response.routes)
{
[_mapView
addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
for (MKRouteStep *step in route.steps){
NSLog(@"%@",step.instructions);
}
}
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]]) {
// Try to dequeue an existing pin view first.
MKPinAnnotationView *pinView = (MKPinAnnotationView*)[self.mapView dequeueReusableAnnotationViewWithIdentifier:@"CustomPinAnnotationView"];
if (!pinView)
{
// If an existing pin view was not available, create one.
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
} else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
-(void)getRoute {
[self getLocationFromString];
MKDirectionsRequest *directionsRequest = [[MKDirectionsRequest alloc] init];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:thePlacemark];
[directionsRequest setSource:[MKMapItem mapItemForCurrentLocation]];
[directionsRequest setDestination:[[MKMapItem alloc] initWithPlacemark:placemark]];
directionsRequest.transportType = MKDirectionsTransportTypeAutomobile;
MKDirections *directions = [[MKDirections alloc] initWithRequest:directionsRequest];
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (error) {
NSLog(@"Error %@", error.description);
} else {
routeDetails = response.routes.lastObject;
[self.mapView addOverlay:routeDetails.polyline];
}
}];
}
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
MKPolylineRenderer * routeLineRenderer = [[MKPolylineRenderer alloc] initWithPolyline:routeDetails.polyline];
routeLineRenderer.strokeColor = [UIColor redColor];
routeLineRenderer.lineWidth = 5;
return routeLineRenderer;
}
- (IBAction)changeMapType:(id)sender {
if (_mapView.mapType == MKMapTypeStandard)
_mapView.mapType = MKMapTypeSatellite;
else
_mapView.mapType = MKMapTypeStandard;
}
-(void)getLocationFromString{
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:self.agendaEntry.address completionHandler:^(NSArray *placemarks, NSError *error) {
if (error) {
NSLog(@"%@", error);
} else {
thePlacemark = [placemarks lastObject];
float spanX = 1.00725;
float spanY = 1.00725;
MKCoordinateRegion region;
region.center.latitude = thePlacemark.location.coordinate.latitude;
region.center.longitude = thePlacemark.location.coordinate.longitude;
region.span = MKCoordinateSpanMake(spanX, spanY);
[self.mapView setRegion:region animated:YES];
[self addAnnotation:thePlacemark];
}
}];
}
@end
我对此还比较陌生,所以其中一些可能是错误的。我想要的是,当我按下一个按钮(在另一个视图中)时,"agendaEntry"会在segue上传递。它包含一个带有地址的字符串,该地址被向前地理编码,地图显示从用户所在地到该字符串中地址的方向/路线。
我不知道如何让它显示驾驶/步行方向或显示多条路线。但对于初学者来说,如果它能起作用,那就太好了。
它之所以不绘制方向,是因为方向请求是在目标占位符(thePlacemark
)实际上由geocodeAddressString
完成处理程序块设置之前发出的。
注意文档中关于geocodeAddressString:completionHandler:
:的说明
此方法将指定的位置数据异步提交给地理编码服务器并返回。
因此,即使在方向请求之前调用了getLocationFromString
(调用geocodeAddressString
),在geocodeAddressString
启动(但未完成)之后,执行会立即返回并在getRoute
中继续。
因此,当getRoute
设置directionsRequest
时,thePlacemark
仍然是nil
,并且您可能会记录一个错误,例如"方向不可用"。
为此,您可以将对directions请求设置代码的调用移动到geocodeAddressString
完成处理程序块内的(在添加注释代码之后)。
有三件事需要改变:
- 在
viewDidLoad
中,执行[self getLocationFromString];
而不是[self getRoute];
- 在
getRoute
中,删除对getLocationFromString
的调用 - 在
getLocationFromString
中,在完成处理程序块中,在[self addAnnotation:thePlacemark];
之后,执行[self getRoute];
关于显示多条路线,首先您需要实际请求备用路线(默认为NO
):
directionsRequest.requestsAlternateRoutes = YES;
您可能遇到的问题的另一部分是由于rendererForOverlay
:中的这一行
MKPolylineRenderer * routeLineRenderer = [[MKPolylineRenderer alloc]
initWithPolyline:routeDetails.polyline];
它使用外部实例变量而不是为委托方法提供的overlay
参数来创建多段线渲染器。这基本上意味着委托方法只适用于一个特定的覆盖层(routeDetails.polyline
),并且由于无法控制映射视图何时调用委托方法,因此无法从委托方法外部可靠地设置routeDetails.polyline
以确保它指向正确的覆盖层。每个备用路线都是一条单独的折线,地图视图将对每条路线分别调用rendererForOverlay
。
相反,使用overlay
参数创建多段线渲染器(首先检查overlay
是否为MKPolyline
):
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
if ([overlay isKindOfClass:[MKPolyline class]])
{
MKPolylineRenderer * routeLineRenderer =
[[MKPolylineRenderer alloc] initWithPolyline:overlay];
routeLineRenderer.strokeColor = [UIColor redColor];
routeLineRenderer.lineWidth = 5;
return routeLineRenderer;
}
return nil;
}
然后在getRoute
中,而不是这样:
routeDetails = response.routes.lastObject;
[self.mapView addOverlay:routeDetails.polyline];
调用您已经拥有的showRoute
方法,该方法会添加所有路由:
[self showRoute:response];