xcode MKMapView 缩放用户位置和注释

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14760582/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 02:44:25  来源:igfitidea点击:

MKMapView zoom User Location and Annotation

objective-cxcode

提问by Luciano Nascimento

I want my MKMapView to zoom 'User Location' and the Annotation as close as possible. The map already show both, but is zoomed out to the whole country. How can I do that?

我希望我的 MKMapView 尽可能接近缩放“用户位置”和注释。地图已显示两者,但已缩小到整个国家/地区。我怎样才能做到这一点?

And I don't know why the Annotation and Pin are not animated.

而且我不知道为什么 Annotation 和 Pin 没有动画。

My Code:

我的代码:

//Coords User
CLLocationCoordinate2D user_location;
user_location.latitude = mapView.userLocation.location.coordinate.latitude;
user_location.longitude = mapView.userLocation.location.coordinate.longitude;
//Coords Annotation
CLLocationCoordinate2D club_location;
club_location.latitude = [self.clubInfo.latitude doubleValue];
club_location.longitude = [self.clubInfo.longitude doubleValue];

MKMapPoint userPoint = MKMapPointForCoordinate(user_location);
MKMapPoint annotationPoint = MKMapPointForCoordinate(club_location);

MKMapRect userRect = MKMapRectMake(userPoint.x, userPoint.y, 0, 0);
MKMapRect annotationRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);

MKMapRect unionRect = MKMapRectUnion(userRect, annotationRect);

MKMapRect unionRectThatFits = [mapView mapRectThatFits:unionRect];
[mapView setVisibleMapRect:unionRectThatFits animated:YES];

// Add an annotation
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
annotation.coordinate = club_location;
annotation.title = self.clubInfo.clubName;
annotation.subtitle = @"Pin!";
[mapView addAnnotation:annotation]; // This was missing
[mapView selectAnnotation:annotation animated:YES];

MapView

地图视图

Logs:

日志:

userRect: {{134217728.0, 134217728.0}, {0.0, 0.0}}
annotationRect: {{99775488.0, 152579328.0}, {0.0, 0.0}}

unionRect: {{99775488.0, 134217728.0}, {34442240.0, 18361600.0}}

mapView.visibleMapRect: {{96025087.6, 116070015.1}, {41943040.7, 54657025.8}}

回答by Tricertops

If I understand well, you want those two annotations to be visible with maximum possible zoom. I found this solution that does not reqire any calculations.

如果我理解得很好,您希望这两个注释以最大可能的缩放比例可见。我发现这个解决方案不需要任何计算

// You have coordinates
CLLocationCoordinate2D user = ...;
CLLocationCoordinate2D annotation = ...;
// Make map points
MKMapPoint userPoint = MKMapPointForCoordinate(user);
MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation);
// Make map rects with 0 size
MKMapRect userRect = MKMapRectMake(userPoint.x, userPoint.y, 0, 0);
MKMapRect annotationRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);
// Make union of those two rects
MKMapRect unionRect = MKMapRectUnion(userRect, annotationRect);
// You have the smallest possible rect containing both locations
MKMapRect unionRectThatFits = [mapView mapRectThatFits:unionRect];
[mapView setVisibleMapRect:unionRectThatFits animated:YES];

CoreLocation and MapKit structures are hell.

CoreLocation 和 MapKit 结构是地狱。

回答by Arjan

For anyone coming here later: The shortest way of doing this is (iOS7+) this:

对于以后来这里的任何人:这样做的最短方法是(iOS7+):

Assuming you have a @property MKMapView *mapView, and an MKPointAnnotation *theAnnotation, call:

假设您有一个 @propertyMKMapView *mapView和一个MKPointAnnotation *theAnnotation, 调用:

[self.mapView showAnnotations:@[theAnnotation, self.mapView.userLocation] animated:NO];

Now this could cause some problems if called too early (i.e. when self.mapView.userLocationis not yet set). If so, you can call in viewWillAppear:

现在,如果过早调用(即何时self.mapView.userLocation尚未设置),这可能会导致一些问题。如果是这样,您可以调用viewWillAppear

[self.mapView.userLocation addObserver:self forKeyPath:@"location" options:0 context:NULL];

Then, implement:

然后,实施:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"location"]) {
        [self.mapView showAnnotations:@[theAnnotation, self.mapView.userLocation] animated:NO];
    }
}

That way you're sure it's set. Don't forget to remove the observer at viewWillDisappear:

这样你就确定它已经设置好了。不要忘记在 viewWillDisappear 处移除观察者:

[self.mapView.userLocation removeObserver:self forKeyPath:@"location"];

回答by 9to5ios

Use these 4 classes - it works like a charm!

使用这 4 个类 - 它就像一个魅力!

//MapViewController.h file

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@interface MapViewController : UIViewController <CLLocationManagerDelegate>  {
    IBOutlet UIButton *buttonBack;
    IBOutlet MKMapView *mapView;
    IBOutlet UILabel *labelTitle;
    NSString *lon,*lat,*nickName;
    BOOL isFirstLaunch;
}
@property(nonatomic,retain) NSString *lon,*lat,*nickName;
@property(nonatomic,retain) IBOutlet UIButton *buttonBack;
@property(nonatomic,retain) IBOutlet UILabel *labelTitle;
@property(nonatomic,retain) IBOutlet MKMapView *mapView;
-(IBAction)buttonBackAction:(UIButton *)_btn;
-(void)zoomToFitMapAnnotations;
@end

// // MapViewController.m //

// // MapViewController.m //

#import "MapViewController.h"
#import "Annotation.h"


@implementation MapViewController
@synthesize buttonBack,mapView,labelTitle;
@synthesize lon,lat,nickName;

// The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
/*
 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
 self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
 if (self) {
 // Custom initialization.
 }
 return self;
 }
 */
-(IBAction)buttonBackAction:(UIButton *)_btn{
    [self.navigationController popViewControllerAnimated:1];
}


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    CLLocationManager* locationManager = [[CLLocationManager alloc] init];
    [locationManager setDelegate:self];
    [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [locationManager startUpdatingLocation];
    NSLog(@"MapViewController");
    labelTitle.text = @"anscacorona.blogspot.in"
    CLLocationCoordinate2D location;
    location.latitude = [self.lat floatValue];
    location.longitude = [self.lon floatValue];

    Annotation *annotation = [[Annotation alloc] init];
    annotation.theCoordinate = location;
    annotation.theTitle = [NSString stringWithFormat:@"%@",labelTitle.text];

    [mapView addAnnotation:annotation];
    [annotation release];
    mapView.showsUserLocation = 1;

    [self zoomToFitMapAnnotations];
    [super viewDidLoad];
}

// Shows the location of both users. called when the device location changes to move the map accordinly. necessary ONLY once when the window is opened. afterwards the user can move the map as he choises. 
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    if (isFirstLaunch) {
        CLLocationCoordinate2D topLeftCoord;
        CLLocationCoordinate2D bottomRightCoord;

        topLeftCoord.longitude = fmin([self.lon floatValue], newLocation.coordinate.longitude);
        topLeftCoord.latitude = fmax([self.lat floatValue], newLocation.coordinate.latitude);

        bottomRightCoord.longitude = fmax([self.lon floatValue], newLocation.coordinate.longitude);
        bottomRightCoord.latitude = fmin([self.lat floatValue], newLocation.coordinate.latitude);

        MKCoordinateRegion region;
        region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
        region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
        region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.5; // Add a little extra space on the sides
        region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.5;  // Add a little extra space on the sides

        region = [mapView regionThatFits:region];
        [mapView setRegion:region animated:YES];
        isFirstLaunch = NO;
    }

}

-(void)zoomToFitMapAnnotations
{
    if([mapView.annotations count] == 0)
        return;

    CLLocationCoordinate2D topLeftCoord;
    CLLocationCoordinate2D bottomRightCoord;
    topLeftCoord.longitude = fmin(mapView.userLocation.location.coordinate.longitude, [self.lon floatValue]);
    topLeftCoord.latitude = fmax(mapView.userLocation.location.coordinate.latitude, [self.lat floatValue]);

    bottomRightCoord.longitude = fmax(mapView.userLocation.location.coordinate.longitude, [self.lon floatValue]);
    bottomRightCoord.latitude = fmin(mapView.userLocation.location.coordinate.latitude, [self.lat floatValue]);


    MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };

    CLLocationCoordinate2D userCoord = {[self.lat floatValue],[self.lon floatValue]};
    region.center = userCoord;
    region.span.latitudeDelta = 0.05f;//fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; // Add a little extra space on the sides
    region.span.longitudeDelta = 0.05f;//fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1;  // Add a little extra space on the sides

    [mapView setRegion:region animated:YES];
    [mapView regionThatFits:region];
}
/*
 // Override to allow orientations other than the default portrait orientation.
 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
 // Return YES for supported orientations.
 return (interfaceOrientation == UIInterfaceOrientationPortrait);
 }
 */

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc. that aren't in use.
}
#pragma mark - View Lifecycle

-(void)viewWillAppear:(BOOL)animated{
    isFirstLaunch=YES;
}

- (void)viewDidUnload {
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}


- (void)dealloc {

    [super dealloc];
}


@end

//anotation classes- Annotation.h

//注解类- Annotation.h

#import <MapKit/MapKit.h>


@interface Annotation : NSObject  <MKAnnotation>{
    CLLocationCoordinate2D theCoordinate;
    NSString *theTitle;
    NSString *restId;
    NSString *theSubtitle;
}
@property(nonatomic,retain) NSString *restId;
@property(nonatomic,retain) NSString *theTitle;
@property(nonatomic,retain) NSString *theSubtitle;
@property CLLocationCoordinate2D theCoordinate;
@end

//Annotation.m

//注解.m

#import "Annotation.h"


@implementation Annotation
@synthesize theCoordinate,theTitle,theSubtitle,restId;
- (CLLocationCoordinate2D)coordinate;
{
    return theCoordinate; 
}

// required if you set the MKPinAnnotationView's "canShowCallout" property to YES
- (NSString *)title
{
    return theTitle;
}

// optional
- (NSString *)subtitle
{
    return theSubtitle;
}

- (void)dealloc
{
    [super dealloc];
}

@end