文章

在 MKMapView 原生地图上显示当前位置的朝向(设备的朝向)

想在 MKMapView 地图上显示用户位置指向角,苹果官方并没有把 MKModernUserLocationView 暴露给开发者使用,所以只能自己添加朝向的箭头图片。

实现

.h文件

1
2
3
4
5
6
7
8
#import <UIKit/UIKit.h>

@interface LHUserLocationHeadingView : UIView

- (void)startUpdatingHeading;
- (void)stopUpdatingHeading;

@end

.m文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#import "LHUserLocationHeadingView.h"
#import <CoreLocation/CoreLocation.h>

@interface LHUserLocationHeadingView()<CLLocationManagerDelegate>

@property (nonatomic, strong) UIImageView *arrowImageView;
@property (nonatomic, strong) CLLocationManager *locationManager;

@end

@implementation AAUserLocationHeadingView

- (instancetype)initWithFrame:(CGRect)frame {
    
    if (self = [super initWithFrame:frame]) {
        [self commonInit];
    }
    
    return self;
}

- (UIImageView *)arrowImageView {
    if (_arrowImageView == nil) {
        _arrowImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"xz_loction_heading_arrow"]];
    }
    
    return _arrowImageView;
}

- (CLLocationManager *)locationManager {
    if (_locationManager == nil) {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
    }
    
    return _locationManager;
}

- (void)commonInit {
    self.backgroundColor = [UIColor clearColor];
    self.arrowImageView.frame = self.frame;
    [self addSubview:self.arrowImageView];
    [self startUpdatingHeading];
}

- (void)startUpdatingHeading {
    [self.locationManager startUpdatingHeading];
}

- (void)stopUpdatingHeading {
    [self.locationManager stopUpdatingHeading];
}

#pragma mark -- CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
    if (newHeading.headingAccuracy < 0) {
        return;
    }
    
    CLLocationDirection heading = newHeading.trueHeading > 0 ? newHeading.trueHeading : newHeading.magneticHeading;
    CGFloat rotation =  heading / 180 * M_PI;
    self.arrowImageView.transform = CGAffineTransformMakeRotation(rotation);
}


使用

在地图初始化时会掉用这个代理方法,可以判断是否是私有对象 MKModernUserLocationView,来添加自定义的控件在上面

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews (NSArray<MKAnnotationView *> *)views {
    
    if ([views.lastObject isKindOfClass:NSClassFromString(@"MKModernUserLocationView")]) {
        
        AAUserLocationHeadingView *headingView = [[AAUserLocationHeadingView alloc] initWithFrame:CGRectMake(0, 0, 36, 36)];
        headingView.center = CGPointMake(views.lastObject.width/2, views.lastObject.height / 2);
        headingView.tag = 312;
        if (![views.lastObject viewWithTag:312]) {
            [views.lastObject addSubview:headingView];
            _userHeadingView = headingView;
        }
    }  
}


1
2
3
// 在Map不在屏幕显示时记得停止获取方向 进入时再开始
[_userHeadingView startUpdatingHeading];
[_userHeadingView stopUpdatingHeading];


1
2
// 在跟随模式下记得隐藏,其他模式下显示
_userHeadingView.hidden = YES;
本文由作者按照 CC BY 4.0 进行授权