Позиціонування MKMapView для відображення кількох анотацій одночасно


92

У мене є кілька приміток, які я хочу додати до свого MKMapView (це може 0-n елементів, де n, як правило, близько 5). Я можу додати примітки до штрафу, але хочу змінити розмір карти, щоб одразу помістити всі анотації на екрані, і я не знаю, як це зробити.

Я дивився, -regionThatFits:але не зовсім впевнений, що з цим робити. Я опублікую якийсь код, щоб показати, що я маю досі. Я думаю, що це, як правило, просто завдання, але я відчуваю, що поки що переповнений MapKit.

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{

location = newLocation.coordinate;
//One location is obtained.. just zoom to that location

MKCoordinateRegion region;
region.center = location;

//Set Zoom level using Span
MKCoordinateSpan span;
span.latitudeDelta = 0.015;
span.longitudeDelta = 0.015;
region.span = span;
// Set the region here... but I want this to be a dynamic size
// Obviously this should be set after I've added my annotations
[mapView setRegion:region animated:YES];

// Test data, using these as annotations for now
NSArray *arr = [NSArray arrayWithObjects:@"one", @"two", @"three", @"four", nil];
float ex = 0.01;
for (NSString *s in arr) {
    JBAnnotation *placemark = [[JBAnnotation alloc] initWithLat:(location.latitude + ex) lon:location.longitude];
    [mapView addAnnotation:placemark];
    ex = ex + 0.005;
}
    // What do I do here?
    [mapView setRegion:[mapView regionThatFits:region] animated:YES];
}

Зверніть увагу, це все відбувається, коли я отримую оновлення місцезнаходження ... Я не знаю, чи це відповідне місце для цього. Якщо ні, де було б краще місце? -viewDidLoad?

Заздалегідь спасибі.

Відповіді:



137

Посилання Написала Джим тепер мертва, але я був в змозі знайти код (який я мав ятати де - то). Сподіваюся, це допомагає.

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

    CLLocationCoordinate2D topLeftCoord; 
    topLeftCoord.latitude = -90; 
    topLeftCoord.longitude = 180; 

    CLLocationCoordinate2D bottomRightCoord; 
    bottomRightCoord.latitude = 90; 
    bottomRightCoord.longitude = -180; 

    for(id<MKAnnotation> annotation in mapView.annotations) { 
        topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude); 
        topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude); 
        bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude); 
        bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.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;      

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

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

14
Я міг би поцілувати тебе. Це просто заощадило мені купу часу. Я додав код до вищевказаного, щоб обробити 1 місцеположення. Це трохи наблизилось і особисто. Я опублікую це як відповідь, оскільки коментарі, як правило, жують код.
Майкл Рід

Велике спасибі. Я додав це до підкласу MKMapViewта змінив метод на - (void) zoomToFitAnnotations:(BOOL)animated. Працює ідеально!
simonbs

1
це працює дуже добре. також це корисно. ви можете змінити зменшення чи збільшення масштабу. so region.span.latitudeDelta = fabs (topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; /// змінити значення. при збільшенні значення: зменшення масштабу ........ при зменшенні значення: збільшення наприклад: region.span.latitudeDelta = fabs (topLeftCoord.latitude - bottomRightCoord.latitude) * 4.1;
Ерхан Демірчі

1
@ MR.Mustafa: Це працює, приголомшливо! Але я думаю, що вирішити питання достатньо. Тож будь ласка, хтось поясни мені, як це працює. Або через будь-які посилання. Вибачте, якщо я дурний, я початківець. Підтримка Pls. Дякую
Сиддарт Грайд

1
@ Мустафа ... Дякую, що це врятувало мені день.
Vvk

133

Чому так складно?

MKCoordinateRegion coordinateRegionForCoordinates(CLLocationCoordinate2D *coords, NSUInteger coordCount) {
    MKMapRect r = MKMapRectNull;
    for (NSUInteger i=0; i < coordCount; ++i) {
        MKMapPoint p = MKMapPointForCoordinate(coords[i]);
        r = MKMapRectUnion(r, MKMapRectMake(p.x, p.y, 0, 0));
    }
    return MKCoordinateRegionForMapRect(r);
}

6
неймовірно, наскільки простішим, чистішим і простішим це є, ніж розміщені альтернативи. насправді ви можете ще більше спростити це, оскільки не потрібно перетворюватись у MKCoordinateRegion - просто зателефонуйте на setVisibleMapRect: на свій MKMapView з MKMapRect, який ви створюєте тут.
лінзовет

2
Анотації іноді наклеюються на верхню частину карти і не видно. Будь-який внесок щодо найкращого підходу до збільшення масштабу після створення MKCoordinateRegion?
Кайл C

3
@KyleC[mapView setVisibleMapRect:mapRect edgePadding:UIEdgeInsetsMake(20.0f, 20.0f, 20.0f, 20.0f) animated:animated];
користувач

Як створити CLLocationCoordinate2D *coordsмасив? Використовуючи malloc()?
Hlung

3
@KyleC. Я додав це до повернення, rяке в основному зменшує 20 відсотківCGFloat zoomOutPercent = 0.2f; r = MKMapRectMake(r.origin.x-r.size.width*zoomOutPercent, r.origin.y-r.size.height*zoomOutPercent, r.size.width*(1+zoomOutPercent*2), r.size.height*(1+zoomOutPercent*2));
Loozie

44

Я зробив щось подібне до цього, щоб зменшити масштаб (або в зоні) на область, яка включала анотацію точок та поточне місцеположення. Ви можете розширити це, переглянувши свої примітки.

Основні етапи:

  • Обчисліть мінімум лат / довго
  • Обчисліть максимум лат / довго
  • Створіть об'єкти CLLocation для цих двох точок
  • Обчисліть відстань між точками
  • Створіть область, використовуючи центральну точку між точками та відстані, перетвореною на градуси
  • Перемістіть регіон у MapView, щоб налаштувати
  • Використовуйте скоригований регіон, щоб встановити регіон MapView
    -(IBAction)zoomOut:(id)sender {

        CLLocationCoordinate2D southWest = _newLocation.coordinate;
        CLLocationCoordinate2D northEast = southWest;

        southWest.latitude = MIN(southWest.latitude, _annotation.coordinate.latitude);
        southWest.longitude = MIN(southWest.longitude, _annotation.coordinate.longitude);

        northEast.latitude = MAX(northEast.latitude, _annotation.coordinate.latitude);
        northEast.longitude = MAX(northEast.longitude, _annotation.coordinate.longitude);

        CLLocation *locSouthWest = [[CLLocation alloc] initWithLatitude:southWest.latitude longitude:southWest.longitude];
        CLLocation *locNorthEast = [[CLLocation alloc] initWithLatitude:northEast.latitude longitude:northEast.longitude];

        // This is a diag distance (if you wanted tighter you could do NE-NW or NE-SE)
        CLLocationDistance meters = [locSouthWest getDistanceFrom:locNorthEast];

        MKCoordinateRegion region;
        region.center.latitude = (southWest.latitude + northEast.latitude) / 2.0;
        region.center.longitude = (southWest.longitude + northEast.longitude) / 2.0;
        region.span.latitudeDelta = meters / 111319.5;
        region.span.longitudeDelta = 0.0;

        _savedRegion = [_mapView regionThatFits:region];
        [_mapView setRegion:_savedRegion animated:YES];

        [locSouthWest release];
        [locNorthEast release];
    }

Це схоже на шлях. Дякую!
jbrennan

1
Нам вдалося змусити це працювати, використовуючи MKCoordinateRegionMake: gist.github.com/1599700 у випадку, якщо хтось все ще хоче зробити це таким чином.
чакрит

region.center.latitude = (південний захід.латута + північний схід.шляху) / 2,0; Дякую за це
Тоні

Чи працює це з точками по обидва боки від меридіана? Екватор?
Еліот

1
Цей код розміщує місцеположення на екрані, коли вони мають аналогічне значення y. Наприклад, показ двох локацій на (50, -4) та (100, -3) занадто далеко збільшить карту, розміщуючи координати з лівої та правої частини екрана.
користувач

21

У мене інша відповідь. Я збирався сам реалізувати алгоритм масштабування, але я подумав, що в Apple має бути спосіб зробити те, що ми хотіли, не маючи великої праці. Використання doco API швидко показало, що я можу використовувати MKPolygon, щоб зробити те, що потрібно:

/* this simply adds a single pin and zooms in on it nicely */
- (void) zoomToAnnotation:(MapAnnotation*)annotation {
    MKCoordinateSpan span = {0.027, 0.027};
    MKCoordinateRegion region = {[annotation coordinate], span};
    [mapView setRegion:region animated:YES];
}

/* This returns a rectangle bounding all of the pins within the supplied
   array */
- (MKMapRect) getMapRectUsingAnnotations:(NSArray*)theAnnotations {
    MKMapPoint points[[theAnnotations count]];

    for (int i = 0; i < [theAnnotations count]; i++) {
        MapAnnotation *annotation = [theAnnotations objectAtIndex:i];
        points[i] = MKMapPointForCoordinate(annotation.coordinate);
    }

    MKPolygon *poly = [MKPolygon polygonWithPoints:points count:[theAnnotations count]];

    return [poly boundingMapRect];
}

/* this adds the provided annotation to the mapview object, zooming 
   as appropriate */
- (void) addMapAnnotationToMapView:(MapAnnotation*)annotation {
    if ([annotations count] == 1) {
        // If there is only one annotation then zoom into it.
        [self zoomToAnnotation:annotation];
    } else {
        // If there are several, then the default behaviour is to show all of them
        //
        MKCoordinateRegion region = MKCoordinateRegionForMapRect([self getMapRectUsingAnnotations:annotations]);

        if (region.span.latitudeDelta < 0.027) {
            region.span.latitudeDelta = 0.027;
        }

        if (region.span.longitudeDelta < 0.027) {
            region.span.longitudeDelta = 0.027;
        }
        [mapView setRegion:region];
    }

    [mapView addAnnotation:annotation];
    [mapView selectAnnotation:annotation animated:YES];
}

Сподіваюся, це допомагає.


Немає проблем. Зазвичай існує кращий спосіб, якщо ви бажаєте і маєте час витратити на це.
PKCLsoft

Я виявив, що це ставить шпильки трохи занадто близько до краю екрана. Спробуйте додати анотаціїRegion.span.latitudeDelta = annotationsRegion.span.latitudeDelta * kEventMapDetailBorderFactor; безпосередньо перед setRegion.
Адам Ебербах

Ви маєте рацію @AdamEberbach, але, схоже, ваш кліп містить константу, яка недоступна. Ви знайшли значення, яке забезпечило «приємну» межу навколо шпильок?
PKCLsoft

Відповідь командира коду нижче про використання нового методу showAnnotations з iOS7 додає хороший запас, який насправді працює краще, хоча цей код і крутіший.
Джеймс Тумі

14

Ви також можете зробити це таким чином ..

// Position the map so that all overlays and annotations are visible on screen.
MKMapRect regionToDisplay = [self mapRectForAnnotations:annotationsToDisplay];
if (!MKMapRectIsNull(regionToDisplay)) myMapView.visibleMapRect = regionToDisplay;

- (MKMapRect) mapRectForAnnotations:(NSArray*)annotationsArray
{
    MKMapRect mapRect = MKMapRectNull;

    //annotations is an array with all the annotations I want to display on the map
    for (id<MKAnnotation> annotation in annotations) { 

        MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
        MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);

        if (MKMapRectIsNull(mapRect)) 
        {
            mapRect = pointRect;
        } else 
        {
            mapRect = MKMapRectUnion(mapRect, pointRect);
        }
    }

     return mapRect;
}

13

На основі інформації та пропозицій усіх я придумав таке. Дякуємо всім, хто беруть участь у цій дискусії за свій внесок :) Це стосується контролера подання, який містить mapView.

- (void)zoomToFitMapAnnotations { 

if ([self.mapView.annotations count] == 0) return; 

int i = 0;
MKMapPoint points[[self.mapView.annotations count]];

//build array of annotation points
for (id<MKAnnotation> annotation in [self.mapView annotations])
        points[i++] = MKMapPointForCoordinate(annotation.coordinate);

MKPolygon *poly = [MKPolygon polygonWithPoints:points count:i];

[self.mapView setRegion:MKCoordinateRegionForMapRect([poly boundingMapRect]) animated:YES]; 
}

Це повинно отримати більше голосів. Дуже точний і суттєвий.
Наташа

5

У моєму випадку я починаю з об’єктів CLLocation і створюю анотації до кожного з них.
Мені потрібно розмістити лише дві анотації, тому я маю простий підхід до створення масиву точок, але його можна було легко розширити, щоб створити масив з довільною довжиною з заданим набором CLLocations.

Ось моя реалізація (не вимагає створення MKMapPoints):

//start with a couple of locations
CLLocation *storeLocation = store.address.location.clLocation;
CLLocation *userLocation = [LBLocationController sharedController].currentLocation;

//build an array of points however you want
CLLocationCoordinate2D points[2] = {storeLocation.coordinate, userLocation.coordinate};

//the magic part
MKPolygon *poly = [MKPolygon polygonWithCoordinates:points count:2];
[self.mapView setRegion:MKCoordinateRegionForMapRect([poly boundingMapRect])];

5

Використовуючи Swift, багатокутник і деякі додаткові накладки, я використав наступне:

func zoomToFit() {
    var allLocations:[CLLocationCoordinate2D] = [
        CLLocationCoordinate2D(latitude: 32.768805, longitude: -117.167119),
        CLLocationCoordinate2D(latitude: 32.770480, longitude: -117.148385),
        CLLocationCoordinate2D(latitude: 32.869675, longitude: -117.212929)
    ]

    var poly:MKPolygon = MKPolygon(coordinates: &allLocations, count: allLocations.count)

    self.mapView.setVisibleMapRect(poly.boundingMapRect, edgePadding: UIEdgeInsetsMake(40.0, 40.0, 40.0, 40.0), animated: false)
}


setVisibleMapRect (...). Я займався математикою сам ... погано.
CodeReaper

3

В iOS 7, який ви можете використовувати, є новий метод "MKMapView"

Декларація

SWIFT

func showAnnotations(_ annotations: [AnyObject]!,
            animated animated: Bool)

ЗАВДАННЯ-С

- (void)showAnnotations:(NSArray *)annotations
               animated:(BOOL)animated

Параметри

анотації Анотації, які потрібно бачити на карті. анімовано ТАК, якщо ви хочете, щоб анімація зміни на карті мапи, або НІ, якщо ви хочете, щоб карта відразу відображала новий регіон без анімації.

Обговорення

Виклик цього методу оновлює значення властивості регіону та потенційно інших властивостей для відображення нової області карти.


3

Я знаю, що це давнє запитання, але, якщо ви хочете відобразити всі анотації ВЖЕ, на карті, використовуйте це:

 mapView.showAnnotations(mapView.annotations, animated: true)

3

Ось еквівалент SWIFT (підтверджено Робота в: Xcode6.1, SDK 8.2) для відповідей Мустафи:

func zoomToFitMapAnnotations() {
    if self.annotations.count == 0 {return}

    var topLeftCoordinate = CLLocationCoordinate2D(latitude: -90, longitude: 180)
    var bottomRightCoordinate = CLLocationCoordinate2D(latitude: 90, longitude: -180)

    for object in self.annotations {
        if let annotation = object as? MKAnnotation {
            topLeftCoordinate.longitude = fmin(topLeftCoordinate.longitude, annotation.coordinate.longitude)
            topLeftCoordinate.latitude = fmax(topLeftCoordinate.latitude, annotation.coordinate.latitude)
            bottomRightCoordinate.longitude = fmax(bottomRightCoordinate.longitude, annotation.coordinate.longitude)
            bottomRightCoordinate.latitude = fmin(bottomRightCoordinate.latitude, annotation.coordinate.latitude)
        }
    }

    let center = CLLocationCoordinate2D(latitude: topLeftCoordinate.latitude - (topLeftCoordinate.latitude - bottomRightCoordinate.latitude) * 0.5, longitude: topLeftCoordinate.longitude - (topLeftCoordinate.longitude - bottomRightCoordinate.longitude) * 0.5)

    print("\ncenter:\(center.latitude) \(center.longitude)")
    // Add a little extra space on the sides
    let span = MKCoordinateSpanMake(fabs(topLeftCoordinate.latitude - bottomRightCoordinate.latitude) * 1.01, fabs(bottomRightCoordinate.longitude - topLeftCoordinate.longitude) * 1.01)
    print("\nspan:\(span.latitudeDelta) \(span.longitudeDelta)")

    var region = MKCoordinateRegion(center: center, span: span)


    region = self.regionThatFits(region)

    self.setRegion(region, animated: true)

}

1
Привіт iOS_Developer. Дякуємо за конверсію Swift. Для мене це не працює, тому що я думаю, що вам не вистачає двох "fmax" замість "fmin" для topLeftCoordinate.latitude та bottomRightCoordinate.longitude.
Філіпп Отто

2

Одним з можливих рішень може бути вимірювання відстані між поточним місцеположенням та всіма примітками та використання методу MKCoordinateRegionMakeWithDistance, щоб зробити область, яка має трохи більшу відстань, ніж найдальша анотація.

Звичайно, це стане повільніше, чим більше доданих вами анотацій.


Я переглядав розділ коментарів лише для того, щоб перевірити себе. Радий, що хтось думає так, як я це робив :-) Оскільки я додаю лише два анотації (початкова та кінцева точка), я не відчував жодної повільності.
thandasoru

2
- (void)zoomToFitMapAnnotations {

if ([self.mapview.annotations count] == 0) return;

int i = 0;
MKMapPoint points[[self.mapview.annotations count]];

//build array of annotation points
for (id<MKAnnotation> annotation in [self.mapview annotations])
    points[i++] = MKMapPointForCoordinate(annotation.coordinate);

MKPolygon *poly = [MKPolygon polygonWithPoints:points count:i];

[self.mapview setRegion:MKCoordinateRegionForMapRect([poly boundingMapRect]) animated:YES];
}

2

На основі чудової відповіді me2(зараз у Swift)

func coordinateRegionForCoordinates(coords: [CLLocationCoordinate2D]) -> MKCoordinateRegion {
    var rect: MKMapRect = MKMapRectNull
    for coord in coords {
        let point: MKMapPoint = MKMapPointForCoordinate(coord)
        rect = MKMapRectUnion(rect, MKMapRectMake(point.x, point.y, 0, 0))
    }
    return MKCoordinateRegionForMapRect(rect)
}

1

Додано трохи, якщо в пункті обробляти 1 розташування - додати до фрагменту коду cound mustufa. Для цього використовується функція zoomToAnnotation pkclSoft:

if ([mapView.annotations count] == 1){
    MKCoordinateSpan span = {0.027, 0.027};
    region.span = span;
    CLLocationCoordinate2D singleCoordinate = [[mapView.annotations objectAtIndex:0] coordinate];
    region.center.latitude = singleCoordinate.latitude;
    region.center.longitude = singleCoordinate.longitude;
}
else
{
    // mustufa's code
}

1

цей код працює для мене, він показує всі шпильки з поточним розташуванням, сподіваюся, це допоможе вам,

func setCenterForMap() {
    var mapRect: MKMapRect = MKMapRectNull
    for loc in mapView.annotations {
        let point: MKMapPoint = MKMapPointForCoordinate(loc.coordinate)
        print( "location is : \(loc.coordinate)");
        mapRect = MKMapRectUnion(mapRect, MKMapRectMake(point.x,point.y,0,0))
    }
    if (locationManager.location != nil) {
        let point: MKMapPoint = MKMapPointForCoordinate(locationManager.location!.coordinate)
        print( "Cur location is : \(locationManager.location!.coordinate)");
        mapRect = MKMapRectUnion(mapRect, MKMapRectMake(point.x,point.y,0,0))
    }

    mapView.setVisibleMapRect(mapRect, edgePadding: UIEdgeInsetsMake(40.0, 40.0, 40.0, 40.0), animated: true)

}

0

Я сподіваюся, що це принаймні актуально, це те, що я зібрав для Mono (на основі відповіді pkclSoft):

void ZoomMap (MKMapView map)
{
    var annotations = map.Annotations;

    if (annotations == null || annotations.Length == 0) 
        return;

    var points = annotations.OfType<MapAnnotation> ()
                            .Select (s => MKMapPoint.FromCoordinate (s.Coordinate))
                            .ToArray ();            

    map.SetVisibleMapRect(MKPolygon.FromPoints (points).BoundingMapRect, true); 
}

0
CLLocationCoordinate2D min = CLLocationCoordinate2DMake(99999.0, 99999.0);
CLLocationCoordinate2D max = CLLocationCoordinate2DMake(-99999.0, -99999.0);

// find max/min....

// zoom to cover area
// TODO: Maybe better using a MKPolygon which can calculate its own fitting region.
CLLocationCoordinate2D center = CLLocationCoordinate2DMake((max.latitude + min.latitude) / 2.0, (max.longitude + min.longitude) / 2.0);
MKCoordinateSpan span = MKCoordinateSpanMake(max.latitude - min.latitude, max.longitude - min.longitude);
MKCoordinateRegion region = MKCoordinateRegionMake(center, span);

[_mapView setRegion:[_mapView regionThatFits:region] animated:YES];

0

На основі відповіді me2 я написав категорію для MKMapView, щоб додати деякі поля та пропустити анотацію про місцезнаходження користувача:

@interface MKMapView (ZoomToFitAnnotations)
- (void)zoomToFitAnnotations:(BOOL)animated;
@end

@implementation MKMapView (ZoomToFitAnnotations)
- (void)zoomToFitAnnotations:(BOOL)animated {
    if (self.annotations.count == 0)
        return;

    MKMapRect rect = MKMapRectNull;
    for (id<MKAnnotation> annotation in self.annotations) {
        if ([annotation isKindOfClass:[MKUserLocation class]] == false) {
            MKMapPoint point = MKMapPointForCoordinate(annotation.coordinate);
            rect = MKMapRectUnion(rect, MKMapRectMake(point.x, point.y, 0, 0));
        }
    }

    MKCoordinateRegion region = MKCoordinateRegionForMapRect(rect);
    region.span.longitudeDelta *= 2; // Margin
    region.span.latitudeDelta *= 2; // Margin
    [self setRegion:region animated:animated];
}
@end

0

Оскільки я не можу коментувати відповідь, я хотів би додати трохи свого зручності у відповідь @ me2 (оскільки я думав, що це найелегантніший підхід, знайдений тут).

Для мого особистого проекту я просто додав категорію класу MKMapView, щоб інкапсулювати функцію "видима область" для загальної версії операції: налаштування, щоб мати можливість бачити всі завантажені в даний час анотації на екземплярі MKMapView. результат був такий:

.h файл

#import <MapKit/MapKit.h>

@interface MKMapView (Extensions)

-(void)ij_setVisibleRectToFitAllLoadedAnnotationsAnimated:(BOOL)animated;
-(void)ij_setVisibleRectToFitAnnotations:(NSArray *)annotations animated:(BOOL)animated;


@end

.m файл

#import "MKMapView+Extensions.h"

@implementation MKMapView (Extensions)

/**
 *  Changes the currently visible portion of the map to a region that best fits all the currently loadded annotations on the map, and it optionally animates the change.
 *
 *  @param animated is the change should be perfomed with an animation.
 */
-(void)ij_setVisibleRectToFitAllLoadedAnnotationsAnimated:(BOOL)animated
{
    MKMapView * mapView = self;

    NSArray * annotations = mapView.annotations;

    [self ij_setVisibleRectToFitAnnotations:annotations animated:animated];

}


/**
 *  Changes the currently visible portion of the map to a region that best fits the provided annotations array, and it optionally animates the change.
    All elements from the array must conform to the <MKAnnotation> protocol in order to fetch the coordinates to compute the visible region of the map.
 *
 *  @param annotations an array of elements conforming to the <MKAnnotation> protocol, holding the locations for which the visible portion of the map will be set.
 *  @param animated    wether or not the change should be perfomed with an animation.
 */
-(void)ij_setVisibleRectToFitAnnotations:(NSArray *)annotations animated:(BOOL)animated
{
    MKMapView * mapView = self;

    MKMapRect r = MKMapRectNull;
    for (id<MKAnnotation> a in annotations) {
        ZAssert([a conformsToProtocol:@protocol(MKAnnotation)], @"ERROR: All elements of the array MUST conform to the MKAnnotation protocol. Element (%@) did not fulfill this requirement", a);
        MKMapPoint p = MKMapPointForCoordinate(a.coordinate);
        //MKMapRectUnion performs the union between 2 rects, returning a bigger rect containing both (or just one if the other is null). here we do it for rects without a size (points)
        r = MKMapRectUnion(r, MKMapRectMake(p.x, p.y, 0, 0));
    }

    [mapView setVisibleMapRect:r animated:animated];

}

@end

Як бачите, до цього часу я додав 2 способи: один для встановлення видимої області карти на той, який підходить для всіх завантажених в даний час анотацій на екземпляр MKMapView, та інший спосіб встановити його для будь-якого масиву об'єктів. Отже, встановити видимий регіон mapView, код буде таким же простим, як:

   //the mapView instance  
    [self.mapView ij_setVisibleRectToFitAllLoadedAnnotationsAnimated:animated]; 

Я сподіваюся, що це допомагає =)


0

Розглянемо це розширення:

extension MKCoordinateRegion {
    init(locations: [CLLocationCoordinate2D], marginMultiplier: Double = 1.1) {
        let mapRect = locations.reduce(MKMapRect(), {
            let point = MKMapPointForCoordinate($1)
            let rect = MKMapRect(origin: point, size: MKMapSize(width: 0.0, height: 0.0))
            return MKMapRectUnion($0, rect)
        })

        var coordinateRegion = MKCoordinateRegionForMapRect(mapRect)
        coordinateRegion.span.latitudeDelta *= marginMultiplier
        coordinateRegion.span.longitudeDelta *= marginMultiplier
        self = coordinateRegion
    }
}

0

Швидка версія 5:

   func regionFor(coordinates coords: [CLLocationCoordinate2D]) -> MKCoordinateRegion {
        var r = MKMapRect.null

        for i in 0 ..< coords.count {
            let p = MKMapPoint(coords[i])

            r = r.union(MKMapRect(x: p.x, y: p.y, width: 0, height: 0))
        }

        return MKCoordinateRegion(r)
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.