iphone - use - map app swift



Zoom MKMapView para encaixar os pinos de anotação? (16)

@ "Não tenho certeza se isso é por causa de alguns outros fatores na minha implementação, mas eu acho que o showAnnotations não faz um zoom / ajuste das anotações como a implementação manual faz, então eu fiquei com o manual um - Ted Avery 17 de abril às 0:35 "

Eu tive o mesmo problema, mas tentei fazer showAnnotations duas vezes (como abaixo) e, por algum motivo, funcionou.

[mapView showAnnotations: yourAnnotationArray animado: YES]; [mapView showAnnotations: yourAnnotationArray animado: YES];

https://ffff65535.com

Eu estou usando o MKMapView e adicionei um número de pinos de anotação ao mapa sobre uma área de 5-10 km. Quando executo o aplicativo meu mapa começa a diminuir o zoom para mostrar o mundo inteiro, qual é a melhor maneira de ampliar o mapa para que os pinos se encaixem na visualização?

EDIT: Meu pensamento inicial seria usar MKCoordinateRegionMake e calcular o centro de coordenadas, longitudeDelta e latitudeDelta de minhas anotações. Tenho certeza que isso vai funcionar, mas eu só queria verificar se não estava faltando nada óbvio.

Código adicionado, BTW: FGLocation é uma classe que está em conformidade com o MKAnnotation , locationFake é um NSMutableArray desses objetos. Comentários são sempre bem vindos ....

- (MKCoordinateRegion)regionFromLocations {
    CLLocationCoordinate2D upper = [[locationFake objectAtIndex:0] coordinate];
    CLLocationCoordinate2D lower = [[locationFake objectAtIndex:0] coordinate];

    // FIND LIMITS
    for(FGLocation *eachLocation in locationFake) {
        if([eachLocation coordinate].latitude > upper.latitude) upper.latitude = [eachLocation coordinate].latitude;
        if([eachLocation coordinate].latitude < lower.latitude) lower.latitude = [eachLocation coordinate].latitude;
        if([eachLocation coordinate].longitude > upper.longitude) upper.longitude = [eachLocation coordinate].longitude;
        if([eachLocation coordinate].longitude < lower.longitude) lower.longitude = [eachLocation coordinate].longitude;
    }

    // FIND REGION
    MKCoordinateSpan locationSpan;
    locationSpan.latitudeDelta = upper.latitude - lower.latitude;
    locationSpan.longitudeDelta = upper.longitude - lower.longitude;
    CLLocationCoordinate2D locationCenter;
    locationCenter.latitude = (upper.latitude + lower.latitude) / 2;
    locationCenter.longitude = (upper.longitude + lower.longitude) / 2;

    MKCoordinateRegion region = MKCoordinateRegionMake(locationCenter, locationSpan);
    return region;
}

A Apple adicionou um novo método para o IOS 7 para simplificar um pouco a vida.

[mapView showAnnotations:yourAnnotationArray animated:YES];

Você pode extrair facilmente de uma matriz armazenada na visualização do mapa:

yourAnnotationArray = mapView.annotations;

e ajuste rapidamente a câmera também!

mapView.camera.altitude *= 1.4;

isso não funcionará a menos que o usuário tenha o iOS 7+ ou o OS X 10.9+ instalado. confira a animação personalizada here


Adicionado este loop If dentro do loop for para excluir o pino de localização dos usuários deste método (necessário no meu caso, e talvez outros)

if (![annotation isKindOfClass:[MKUserLocation class]] ) {

//Code Here...

}

Apenas compartilhando minhas observações sobre isso:

Se você estiver usando xCode> 6 com tamanhos "inferidos" para as telas (consulte "métricas simuladas" no inspetor de arquivos) no storyboard, chamar

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

O viewDidLoad resultará em um nível de zoom muito grande em iPhones com 4 polegadas, pois o layout do mapa ainda está no tamanho das telas mais amplas do storyboard.

Você pode mover sua chamada para showAnnotations... para showAnnotations... . Em seguida, o tamanho do mapa já foi ajustado para a tela menor de um iPhone 4.

Alternativamente, altere o valor "inferido" no inspetor de arquivos em "métricas simuladas" para o iphone de 4 polegadas.


Como Abhishek Bedi aponta em um comentário, para iOS7 encaminhar a melhor maneira de fazer isso é:

//from API docs: 
//- (void)showAnnotations:(NSArray *)annotations animated:(BOOL)animated NS_AVAILABLE(10_9, 7_0);
[self.mapView showAnnotations:self.mapView.annotations animated:YES];

Para meu projeto pessoal (anterior ao iOS7), simplesmente adicionei uma categoria na classe MKMapView para encapsular a funcionalidade "área visível" para uma operação muito comum: defini-la para poder ver todas as anotações atualmente carregadas na instância MKMapView ( isso inclui quantos pinos você tiver colocado, bem como a localização do usuário). o resultado foi este:

arquivo .h

#import <MapKit/MapKit.h>

@interface MKMapView (Extensions)

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


@end

arquivo .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

Como você pode ver, adicionei 2 métodos até agora: um para configurar a região visível do mapa para a que cabe em todas as anotações atualmente carregadas na instância do MKMapView e outro método para defini-la em qualquer matriz de objetos. Então, para definir a região visível do mapView, o código seria tão simples quanto:

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

Espero que ajude =)


Este é o que eu encontrei here que funcionou para mim:

(EDIT: Eu atualizei a solução usando a sugestão do @ Micah para aumentar o pointRect em 0.1 para garantir que o rect não seja infinitesimalmente pequeno!)

MKMapRect zoomRect = MKMapRectNull;
for (id <MKAnnotation> annotation in mapView.annotations)
{
    MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
    MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
    zoomRect = MKMapRectUnion(zoomRect, pointRect);
}
[mapView setVisibleMapRect:zoomRect animated:YES];

Você também pode atualizar isso para incluir o pino userLocation substituindo a primeira linha por:

MKMapPoint annotationPoint = MKMapPointForCoordinate(mapView.userLocation.coordinate);
MKMapRect zoomRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);

Eu criei uma extensão para mostrar todas as anotações usando algum código daqui e de lá rapidamente. Isso não mostrará todas as anotações se elas não puderem ser exibidas, mesmo no nível máximo de zoom.

import MapKit

extension MKMapView {
    func fitAllAnnotations() {
        var zoomRect = MKMapRectNull;
        for annotation in annotations {
            let annotationPoint = MKMapPointForCoordinate(annotation.coordinate)
            let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
            zoomRect = MKMapRectUnion(zoomRect, pointRect);
        }
        setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(20, 20, 20, 20), animated: true)
    }
}

Eu fiz uma pequena modificação do código de Rafael para a categoria MKMapView.

- (void)zoomToFitMapAnnotations {
    if ([self.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 self.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;
    region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; // Add a little extra space on the sides
    region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; // Add a little extra space on the sides

    [self setRegion:[self regionThatFits:region] animated:YES];
}

Graças a jowie eu atualizei minha antiga categoria para uma solução mais elegante. Compartilhamento completo, quase copiar e colar solução pronta

MKMapView + AnnotationsRegion.h

#import <MapKit/MapKit.h>

@interface MKMapView (AnnotationsRegion)

-(void)updateRegionForCurrentAnnotationsAnimated:(BOOL)animated;
-(void)updateRegionForCurrentAnnotationsAnimated:(BOOL)animated edgePadding:(UIEdgeInsets)edgePadding;

-(void)updateRegionForAnnotations:(NSArray *)annotations animated:(BOOL)animated;
-(void)updateRegionForAnnotations:(NSArray *)annotations animated:(BOOL)animated edgePadding:(UIEdgeInsets)edgePadding;

@end

MKMapView + AnnotationsRegion.m

#import "MKMapView+AnnotationsRegion.h"

@implementation MKMapView (AnnotationsRegion)

-(void)updateRegionForCurrentAnnotationsAnimated:(BOOL)animated{
    [self updateRegionForCurrentAnnotationsAnimated:animated edgePadding:UIEdgeInsetsZero];
}
-(void)updateRegionForCurrentAnnotationsAnimated:(BOOL)animated edgePadding:(UIEdgeInsets)edgePadding{
    [self updateRegionForAnnotations:self.annotations animated:animated edgePadding:edgePadding];
}

-(void)updateRegionForAnnotations:(NSArray *)annotations animated:(BOOL)animated{
    [self updateRegionForAnnotations:annotations animated:animated edgePadding:UIEdgeInsetsZero];
}
-(void)updateRegionForAnnotations:(NSArray *)annotations animated:(BOOL)animated edgePadding:(UIEdgeInsets)edgePadding{
    MKMapRect zoomRect = MKMapRectNull;
    for(id<MKAnnotation> annotation in annotations){
        MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
        MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
        zoomRect = MKMapRectUnion(zoomRect, pointRect);
    }
    [self setVisibleMapRect:zoomRect edgePadding:edgePadding animated:animated];
}

@end

Espero que ajude alguém e obrigado novamente jowie!


No uso Swift

mapView.showAnnotations(annotationArray, animated: true)

No objetivo c

[mapView showAnnotations:annotationArray animated:YES];

Se você está procurando pelo iOS 8 e acima , a maneira mais simples de fazer isso é configurar o var layoutMargins: UIEdgeInsets { get set } da sua visualização de mapa antes de chamar func showAnnotations(annotations: [MKAnnotation], animated: Bool)

Por exemplo (Swift 2.1):

@IBOutlet weak var map: MKMapView! {
    didSet {
        map.delegate = self
        map.mapType = .Standard
        map.pitchEnabled = false
        map.rotateEnabled = false
        map.scrollEnabled = true
        map.zoomEnabled = true
    }
}

// call 'updateView()' when viewWillAppear or whenever you set the map annotations
func updateView() {
    map.layoutMargins = UIEdgeInsets(top: 25, left: 25, bottom: 25, right: 25)
    map.showAnnotations(map.annotations, animated: true)
}

Swift 3 Esta é a maneira correta de ajustar todas as anotações no mapa.

func zoomMapaFitAnnotations() {

        var zoomRect = MKMapRectNull
        for annotation in mapview.annotations {

            let annotationPoint = MKMapPointForCoordinate(annotation.coordinate)

            let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0)

            if (MKMapRectIsNull(zoomRect)) {
                zoomRect = pointRect
            } else {
                zoomRect = MKMapRectUnion(zoomRect, pointRect)
            }
        }
        self.mapview.setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(50, 50, 50, 50), animated: true)

    }

Uma maneira compatível com o iOS 7 é usar o seguinte. Primeiro, chame showAnnotation para obter um retângulo com todas as anotações. Depois crie e UIEdgeInset com uma inserção superior da altura do pino. Assim, você garante a exibição do pino inteiro no mapa.

[self.mapView showAnnotations:self.mapView.annotations animated:YES];
MKMapRect rect = [self.mapView visibleMapRect];
UIEdgeInsets insets = UIEdgeInsetsMake(pinHeight, 0, 0, 0);
[self.mapView setVisibleMapRect:rect edgePadding:insets animated:YES];

Você acertou.

Encontre as suas latitudes e longitudes máximas e mínimas, aplique alguma aritmética simples e use o MKCoordinateRegionMake .

Para o iOS 7 e superior, use showAnnotations:animated: MKMapView.h em MKMapView.h :

// Position the map such that the provided array of annotations are all visible to the fullest extent possible. 
- (void)showAnnotations:(NSArray *)annotations animated:(BOOL)animated NS_AVAILABLE(10_9, 7_0);

Em Swift

    var zoomRect = MKMapRectNull;

    for i in 0..<self.map.annotations.count {

        let annotation: MKAnnotation = self.map.annotations[i]

        let annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
        let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
        zoomRect = MKMapRectUnion(zoomRect, pointRect);
    }

    self.map.setVisibleMapRect(zoomRect, animated: true)

    var zoomRect: MKMapRect = MKMapRectNull
    for annotation in mapView.annotations {
        let annotationPoint = MKMapPointForCoordinate(annotation.coordinate)
        let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1)
        zoomRect = MKMapRectUnion(zoomRect, pointRect)
    }
    mapView.setVisibleMapRect(zoomRect, animated: true)