我想在屏幕的所有侧面显示方向图像。例如。如果目标的位置是用户位置的右侧并且在可见 map 区域之外,那么我想添加一个方向图像,如下图所示(绿色注释是用户位置,红色是目标的方向,超出屏幕范围):
执行此操作的标准方法是什么?
最简单的方法是在 map 上方的每个基点处放置四个“指针” View 。然后,随着用户移动 map (使用 mapView:regionDidChangeAnimated:
委托(delegate)方法)确定应该显示哪个指针。隐藏所有其他的;然后显示正确的。此外,对指针应用变换,以便如您所做的那样表示方位角。
以下是具有上述配置的 Storyboard 的屏幕截图:
这是一个示例实现(当然,代码不是最佳的。):
//
// MapViewController.m
// AnimationTest
//
// Created by Scott Atkinson on 4/17/15.
//
#import "MapViewController.h"
@import MapKit;
typedef NS_ENUM(NSInteger, CardinalPoint) {
North,
South,
East,
West
};
@interface MapViewController () <MKMapViewDelegate>
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
// Views that show cardinal points on the map (Only one should be shown at a time)
@property (weak, nonatomic) IBOutlet UIView *northPointerView;
@property (weak, nonatomic) IBOutlet UIView *eastPointerView;
@property (weak, nonatomic) IBOutlet UIView *westPointerView;
@property (weak, nonatomic) IBOutlet UIView *southPointerView;
// Location to show on the map
@property (strong, nonatomic) CLLocation * targetLocation;
@end
@implementation MapViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self hidePointerViews];
// Add the location to the map
self.targetLocation = [[CLLocation alloc] initWithLatitude:37.331898 longitude:-122.029824];
MKPlacemark * placemark = [[MKPlacemark alloc] initWithCoordinate:self.targetLocation.coordinate addressDictionary:nil];
[self.mapView addAnnotation:placemark];
}
// ******************** MKMapViewDelegate ********************
#pragma mark - MKMapViewDelegate
// As the map moves, update the cardinal pointer views
- (void) mapViewMKMapView *)mapView regionDidChangeAnimatedBOOL)animated {
if([self isCurrentLocationVisible] && ![self isTargetLocationVisible]) {
// The user location is visible, but the target is not, so show a pointer
double bearing = [self bearingToLocation:self.targetLocation fromLocation:self.mapView.userLocation.location];
[self showCardinalPointDirection:bearing];
} else {
// Hide the pointers
[self hidePointerViews];
}
}
// ******************** Coordinate Helpers ********************
#pragma mark - Coordinate Helpers
- (BOOL) isCurrentLocationVisible {
return MKMapRectContainsPoint(self.mapView.visibleMapRect,
MKMapPointForCoordinate(self.mapView.userLocation.coordinate));
}
- (BOOL) isTargetLocationVisible {
return MKMapRectContainsPoint(self.mapView.visibleMapRect,
MKMapPointForCoordinate(self.targetLocation.coordinate));
}
// From: http://stackoverflow.com/questions/3925942/cllocation-category-for-calculating-bearing-w-haversine-function
double DegreesToRadians(double degrees) {return degrees * M_PI / 180.0;};
double RadiansToDegrees(double radians) {return radians * 180.0/M_PI;};
/// Calculate the bearing between two points
-(double) bearingToLocationCLLocation *) destinationLocation fromLocationCLLocation *) fromLocation {
double lat1 = DegreesToRadians(fromLocation.coordinate.latitude);
double lon1 = DegreesToRadians(fromLocation.coordinate.longitude);
double lat2 = DegreesToRadians(destinationLocation.coordinate.latitude);
double lon2 = DegreesToRadians(destinationLocation.coordinate.longitude);
double dLon = lon2 - lon1;
double y = sin(dLon) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
double radiansBearing = atan2(y, x);
if(radiansBearing < 0.0)
radiansBearing += 2*M_PI;
return RadiansToDegrees(radiansBearing);
}
// ******************** Pointer View ********************
#pragma mark - Pointer View
- (void) hidePointerViews {
self.northPointerView.hidden =
self.southPointerView.hidden =
self.eastPointerView.hidden =
self.westPointerView.hidden = YES;
}
- (void) showCardinalPointDirectiondouble) bearing {
CardinalPoint point = [self cardinalPointWithBearing:bearing];
// Determine which pointer should be shown based on the bearing
UIView * activePointer;
switch (point) {
case North:
activePointer = self.northPointerView;
break;
case South:
activePointer = self.southPointerView;
break;
case East:
activePointer = self.eastPointerView;
break;
case West:
activePointer = self.westPointerView;
break;
}
// Rotate the pointer to show the bearing
activePointer.transform = CGAffineTransformMakeRotation(DegreesToRadians(bearing));
// Hide all pointers except the pertinent one
[self hidePointerViews];
activePointer.hidden = NO;
}
/// Returns the cardinal point for a given bearing (in Degrees)
- (CardinalPoint) cardinalPointWithBearingdouble) bearing {
if (bearing > 45.0 && bearing <= 135.0) {
return East;
} else if (bearing > 135.0 && bearing <= 225.0) {
return South;
} else if (bearing > 225.0 && bearing <= 315.0) {
return West;
} else {
return North;
}
}
@end
此外,指针旋转基于userLocation
和targetLocation
之间的方位。感觉有点奇怪。根据其他点进行旋转可能更好。也许在那一刻可见区域的中心......
关于ios - 可见区域外的目标注释方向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29271692/
欢迎光临 OStack程序员社区-中国程序员成长平台 (https://ostack.cn/) | Powered by Discuz! X3.4 |