Встановлення рівня масштабування для MKMapView


118

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

Дякую

Відповіді:


200

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

CLLocationCoordinate2D noLocation;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(noLocation, 500, 500);
MKCoordinateRegion adjustedRegion = [self.mapView regionThatFits:viewRegion];          
[self.mapView setRegion:adjustedRegion animated:YES];
self.mapView.showsUserLocation = YES;

Швидкий:

let location = ...
let region = MKCoordinateRegion( center: location.coordinate, latitudinalMeters: CLLocationDistance(exactly: 5000)!, longitudinalMeters: CLLocationDistance(exactly: 5000)!)
mapView.setRegion(mapView.regionThatFits(region), animated: true)

3
Це має бути обрана відповідь. Я спробував багато інших запропонованих рішень, але жодне з них не працювало належним чином. Цей код простий і ефективний.
Леві Робертс

1
Гарна відповідь. Однак масштаб буде різним, залежно від розміру екрана, ні?
Вінзіус

1
Цікаво, що MKCoordinateRegionMakeWithDistanceдосі у Свіфті. Це рішення працює!
LinusGeffarth

47

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

@interface MKMapView (ZoomLevel)

@property (assign, nonatomic) NSUInteger zoomLevel;

- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
                  zoomLevel:(NSUInteger)zoomLevel
                   animated:(BOOL)animated;

@end


@implementation MKMapView (ZoomLevel)

- (void)setZoomLevel:(NSUInteger)zoomLevel {
    [self setCenterCoordinate:self.centerCoordinate zoomLevel:zoomLevel animated:NO];
}

- (NSUInteger)zoomLevel {
    return log2(360 * ((self.frame.size.width/256) / self.region.span.longitudeDelta)) + 1;
}

- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
zoomLevel:(NSUInteger)zoomLevel animated:(BOOL)animated {
    MKCoordinateSpan span = MKCoordinateSpanMake(0, 360/pow(2, zoomLevel)*self.frame.size.width/256);
    [self setRegion:MKCoordinateRegionMake(centerCoordinate, span) animated:animated];
}

@end

Невеликі виправлення:- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(NSUInteger)zoomLevel animated:(BOOL)animated { MKCoordinateSpan span = MKCoordinateSpanMake(0, 360/pow(2, zoomLevel)*self.frame.size.width/256); [self setRegion:MKCoordinateRegionMake(centerCoordinate, span) animated:animated]; }
Монобоно

Дякую! Так, ви праві, я фактично вийняв код із свого проекту, де він був функцією, а не доповненням до MKMapView. Я щойно відредагував код, щоб відобразити вашу корекцію.
quentinadam

1
Який зворотній бік цієї формули для розробки поточного рівня збільшення?
Нік

1
Я думаю, що це так:double z = log2(360 * ((self.mapView.frame.size.width/256) / self.mapView.region.span.longitudeDelta));
Нік

1
@devios, на рівні масштабу 1, весь світ (360 °) вписується в 1 плитку шириною 256 пікселів. При рівні 2-го масштабу весь світ (360 °) вписується в 2 плитки 256px (512px). При рівні 3-го масштабу весь світ (360 °) вписується в 4 плитки 256 пікселів (1024 пікселів) тощо
quentinadam

31

Він не вбудований, але я бачив / використовував цей код. Це дозволяє вам скористатися цим:

[mapView setCenterCoordinate:myCoord zoomLevel:13 animated:YES];

Примітка. Це не мій код, я його не писав, тому не можу взяти на нього кредит


1
Уау, це багато коду, ви б подумали, що його слід вбудувати. дякую. матиме погляд, як це зроблено.
система

1
Ви можете отримати .m та .h файл, додати його до свого проекту, а потім посилати його у контролері перегляду вашої карти та використовувати його так, ніби це метод у MKMapView, о радості категорій!
PostMan

2
Не працював для мене, він просто відображає той же рівень масштабування, як і раніше. Я повинен щось робити не так.
система

17

Ви також можете збільшити масштаб, використовуючи MKCoordinateRegion та встановивши його широту прольоту та довготу. Нижче наведено короткий довідник, і ось посилання на iOS. Це не зробить нічого фантазійного, але повинно дозволити вам встановити масштаб, коли малює карту.


MKCoordinateRegion region;
region.center.latitude = {desired lat};
region.center.longitude = {desired lng};
region.span.latitudeDelta = 1;
region.span.longitudeDelta = 1;
mapView.region = region;

Редагувати 1:

MKCoordinateRegion region;
region.center.latitude = {desired lat};
region.center.longitude = {desired lng};
region.span.latitudeDelta = 1;
region.span.longitudeDelta = 1;
region = [mapView regionThatFits:region];
[mapView setRegion:region animated:TRUE];

1
Це не мало значення для мене, коли я змінюю деякі значення, він просто не завантажує карту.
система

Ви встановлюєте це, коли карта завантажується чи ви намагаєтесь маніпулювати після того, як відбулося завантаження? Ви використовуєте 1 або меншу кількість як свої дельти? Просто намагаюся зрозуміти вимоги.
ДерекH

Я встановив його перед виконанням. Я перевіряв значення вище та нижче 1.
система

1
Хороша відповідь, але спробуйте змінити широту, дельту довготи на 0,1 - це збільшено масштаб.
Даніель Кшицковський

12

Проста реалізація Swift, якщо ви використовуєте торгові точки.

@IBOutlet weak var mapView: MKMapView! {
    didSet {
        let noLocation = CLLocationCoordinate2D()
        let viewRegion = MKCoordinateRegionMakeWithDistance(noLocation, 500, 500)
        self.mapView.setRegion(viewRegion, animated: false)
    }
}

На основі відповіді @ Carnal


12

Швидке впровадження

import Foundation
import MapKit

class MapViewWithZoom: MKMapView {

    var zoomLevel: Int {
        get {
            return Int(log2(360 * (Double(self.frame.size.width/256) / self.region.span.longitudeDelta)) + 1);
        }

        set (newZoomLevel){
            setCenterCoordinate(coordinate:self.centerCoordinate, zoomLevel: newZoomLevel, animated: false)
        }
    }

    private func setCenterCoordinate(coordinate: CLLocationCoordinate2D, zoomLevel: Int, animated: Bool) {
        let span = MKCoordinateSpan(latitudeDelta: 0, longitudeDelta: 360 / pow(2, Double(zoomLevel)) * Double(self.frame.size.width) / 256)
        setRegion(MKCoordinateRegion(center: coordinate, span: span), animated: animated)
    }
}

1
Я не на 100% впевнений, але я гадаю, що коли ви створюєте своє IBOutletдля свого map, ви визначаєте це як MapViewWithZoomпросто MKMapView. Потім ви можете просто встановити рівень збільшення за допомогою map.zoomLevel = 1абоmap.zoomLevel = 0.5
Zonker.in.Geneva

1
деякі коментарі з цього приводу будуть кориснішими. Це працює в Swift 3.
nyxee

Чудове рішення! Але мені це більше подобається як розширення, і є одна дивна річ: щоб насправді зменшити масштаб, потрібно зменшити на 2 схожі місцяmapView.zoomLevel -= 2
Олександр

7

Для Swift 3 це досить швидко вперед:

private func setMapRegion(for location: CLLocationCoordinate2D, animated: Bool)
{
    let viewRegion = MKCoordinateRegionMakeWithDistance(location, <#T##latitudinalMeters: CLLocationDistance##CLLocationDistance#>, <#T##longitudinalMeters: CLLocationDistance##CLLocationDistance#>)
    MapView.setRegion(viewRegion, animated: animated)
}

Просто визначте lat-, long-Meters <CLLocationDistance>і mapView відповідатиме масштабуванню вашим значенням.


Що ви маєте на увазі під "mapView відповідати рівню збільшення вашим значенням"? Я припускаю, що ОП хоче сам встановити рівень збільшення або як би ви це зробили, враховуючи запропонований вами вхід?
riper

6

На основі @ великий AdilSoomro в відповідь . Я придумав це:

@interface MKMapView (ZoomLevel)
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
                  zoomLevel:(NSUInteger)zoomLevel
                   animated:(BOOL)animated;

-(double) getZoomLevel;
@end



@implementation MKMapView (ZoomLevel)

- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
                  zoomLevel:(NSUInteger)zoomLevel animated:(BOOL)animated {
    MKCoordinateSpan span = MKCoordinateSpanMake(0, 360/pow(2, zoomLevel)*self.frame.size.width/256);
    [self setRegion:MKCoordinateRegionMake(centerCoordinate, span) animated:animated];
}


-(double) getZoomLevel {
    return log2(360 * ((self.frame.size.width/256) / self.region.span.longitudeDelta));
}

@end

3

Сподіваюсь, вам допоможе наступний фрагмент коду.

- (void)handleZoomOutAction:(id)sender {
    MKCoordinateRegion newRegion=MKCoordinateRegionMake(mapView.region.center,MKCoordinateSpanMake(mapView.region.s       pan.latitudeDelta/0.5, mapView.region.span.longitudeDelta/0.5));
    [mapView setRegion:newRegion];
}


- (void)handleZoomInAction:(id)sender {
    MKCoordinateRegion newRegion=MKCoordinateRegionMake(mapView.region.center,MKCoordinateSpanMake(mapView.region.span.latitudeDelta*0.5, mapView.region.span.longitudeDelta*0.5));
    [mapView setRegion:newRegion];
}

Ви можете вибрати будь-яке значення замість 0,5, щоб зменшити або збільшити рівень масштабування. Я використовував ці методи при натисканні двох кнопок.


2

Відповідь Swift 2.0 за допомогою NSUserDefaults зберігає та відновлює масштаб та положення карти.

Функція збереження положення та масштабування карти:

func saveMapRegion() {
    let mapRegion = [
        "latitude" : mapView.region.center.latitude,
        "longitude" : mapView.region.center.longitude,
        "latitudeDelta" : mapView.region.span.latitudeDelta,
        "longitudeDelta" : mapView.region.span.longitudeDelta
    ]
    NSUserDefaults.standardUserDefaults().setObject(mapRegion, forKey: "mapRegion")
}

Запускайте функцію кожного разу при переміщенні карти:

func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) 
{
        saveMapRegion();
}

Функція для збереження масштабу та розташування карти:

func restoreMapRegion() 
{
    if let mapRegion = NSUserDefaults.standardUserDefaults().objectForKey("mapRegion") 
    {

        let longitude = mapRegion["longitude"] as! CLLocationDegrees
        let latitude = mapRegion["latitude"] as! CLLocationDegrees
        let center = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)

        let longitudeDelta = mapRegion["latitudeDelta"] as! CLLocationDegrees
        let latitudeDelta = mapRegion["longitudeDelta"] as! CLLocationDegrees
        let span = MKCoordinateSpan(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta)

        let savedRegion = MKCoordinateRegion(center: center, span: span)

        self.mapView.setRegion(savedRegion, animated: false)
    }
}

Додайте це до viewDidLoad:

restoreMapRegion()

1

Я знаю, що це пізня відповідь, але я просто хотів вирішити проблему встановлення рівня збільшення. Відповідь Goldmine чудова, але я виявив, що вона недостатньо добре працює в моєму застосуванні.

При ближчому огляді Goldmine зазначає, що "лінії довготи розташовані однаково між собою в будь-якій точці карти". Це неправда, адже насправді широтні лінії розташовані однаково від -90 (південний полюс) до +90 (північний полюс). Лінії довготи розташовані в їх широкій частині на екваторі, сходячись до точки на полюсах.

Таким чином, я прийняв рішення про використання обчислення широти таким чином:

@implementation MKMapView (ZoomLevel)

- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate
    zoomLevel:(NSUInteger)zoom animated:(BOOL)animated
{
    MKCoordinateSpan span = MKCoordinateSpanMake(180 / pow(2, zoom) * 
        self.frame.size.height / 256, 0);
    [self setRegion:MKCoordinateRegionMake(coordinate, span) animated:animated];
}

@end

Сподіваюся, це допомагає на цій пізній стадії.


Гаразд ігноруйте сказане. Goldmine виправляє лінії довготи, які однаково розташовані, оскільки, звичайно, проекція Меркатора використовується для карт. Мої проблеми з рішенням випливали з іншої незначної помилки в моєму додатку, пов'язаної з підкласифікацією нового класу iOS 7 MKTileOverlay.
gektron

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

1

Швидкий:

Map.setRegion(MKCoordinateRegion(center: locValue, latitudinalMeters: 200, longitudinalMeters: 200), animated: true)

locValue - ваша координата.


1

Тут я викладаю свою відповідь та її роботу для швидкого 4.2 .

Центр MKMapView і збільшити масштаб


Якщо я клацаю тут і перейдіть сторінку вниз і натисніть на посилання там, я опинюся тут , а потім я натискаю тут і зараз я застряг в нескінченному циклі 😏
Matthijs

@Matthijs Я поправив посилання. Будь ласка, перевірте та проголосуйте відповідь.
Ашу

0

Виходячи з відповіді квентінадама

Швидкий 5.1

// size refers to the width/height of your tile images, by default is 256.0
// Seems to get better results using round()
// frame.width is the width of the MKMapView

let zoom = round(log2(360 * Double(frame.width) / size / region.span.longitudeDelta))

Дякую, добре виглядає, коли карта виходить на північ. Але що робити, якщо ви обертаєте карту? Що робити, якщо кут прищіпки інший ніж 0?
pierre23

0

MKMapViewрозширення на основі цієї відповіді (+ точність рівня масштабування з плаваючою комою):

import Foundation
import MapKit

extension MKMapView {
    var zoomLevel: Double {
        get {
            return log2(360 * (Double(self.frame.size.width / 256) / self.region.span.longitudeDelta)) + 1
        }

        set (newZoomLevel){
            setCenterCoordinate(coordinate:self.centerCoordinate, zoomLevel: newZoomLevel, animated: false)
        }
    }

    private func setCenterCoordinate(coordinate: CLLocationCoordinate2D, zoomLevel: Double, animated: Bool) {
        let span = MKCoordinateSpan(latitudeDelta: 0, longitudeDelta: 360 / pow(2, zoomLevel) * Double(self.frame.size.width) / 256)
        setRegion(MKCoordinateRegion(center: coordinate, span: span), animated: animated)
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.