iOS MKMapView apple native map realizes user's current position direction following angle (pointing to triangle)

Because our project is a multi map model. Before the product saw that there was a user's position pointing angle on other maps, we didn't make apple maps
Later, I found that the MKMapView API did not expose the MKModernUserLocationView to developers, so I had to write a post on it myself

First look at the effect.
User's current location


.h file

#import <UIKit/UIKit.h>

@interface LHUserLocationHeadingView : UIView

- (void)startUpdatingHeading;

- (void)stopUpdatingHeading;


.m file

#import "LHUserLocationHeadingView.h"
#import <CoreLocation/CoreLocation.h>

@interface LHUserLocationHeadingView()<CLLocationManagerDelegate>

@property (nonatomic, strong) UIImageView *arrowImageView;

@property (nonatomic, strong) CLLocationManager *locationManager;


@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);


When the Map is initialized, the proxy method will be used to determine whether the private object of the Map, UserLocationView, can be used to add a custom View and cut the Map on it to find the design or you can add any one to see the effect

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views{
    if ([views.lastObject isKindOfClass:NSClassFromString(@"MKModernUserLocationView")]) {
        AAUserLocationHeadingView *headingView = [[AAUserLocationHeadingView alloc]initWithFrame:CGRectMake(0, 0, 36, 36)]; = CGPointMake(views.lastObject.width/2, views.lastObject.height / 2);
        headingView.tag = 312;
        if (![views.lastObject viewWithTag:312]) {
            [views.lastObject addSubview:headingView];
            _userHeadingView = headingView;
//When the Map is not displayed on the screen, remember to stop acquiring direction and enter before starting
   [_userHeadingView startUpdatingHeading];
   [_userHeadingView stopUpdatingHeading];

//Remember to hide display in other modes in follow mode
    _userHeadingView.hidden = YES;

Posted on Wed, 18 Mar 2020 08:28:31 -0700 by rodin