Подтвердить что ты не робот

MKMapView показывает неправильно сохраненную область

Я сохраняю регион карты в по умолчанию пользователя, когда мое приложение iPhone закрывается следующим образом:

MKCoordinateRegion region = mapView.region;
[[NSUserDefaults standardUserDefaults] setDouble:region.center.latitude forKey:@"map.location.center.latitude"];
[[NSUserDefaults standardUserDefaults] setDouble:region.center.longitude forKey:@"map.location.center.longitude"];
[[NSUserDefaults standardUserDefaults] setDouble:region.span.latitudeDelta forKey:@"map.location.span.latitude"];
[[NSUserDefaults standardUserDefaults] setDouble:region.span.longitudeDelta forKey:@"map.location.span.longitude"];

Когда приложение снова запустится, Ш прочитает эти значения так же, чтобы пользователь мог видеть то же самое представление карты, что и в прошлый раз:

MKCoordinateRegion region;

region.center.latitude  = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.latitude"];
region.center.longitude = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.longitude"];
region.span.latitudeDelta  = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.latitude"];
region.span.longitudeDelta = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.longitude"];

NSLog([NSString stringWithFormat:@"Region read  : %f %f %f %f", region.center.latitude, region.center.longitude, region.span.latitudeDelta, region.span.longitudeDelta]);

[mapView setRegion:region];

NSLog([NSString stringWithFormat:@"Region on map: %f %f %f %f", mapView.region.center.latitude, mapView.region.center.longitude, mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta]);

Область, которую я прочитал из пользовательских значений по умолчанию, (не удивительно), точно такая же, как и при ее сохранении. Обратите внимание, что то, что сохраняется, происходит непосредственно с карты, поэтому оно никак не преобразуется. Я вернул его на карту с помощью метода setRegion:, но тогда он отличается!

Примеры результатов:

Region read  : 50.241110 8.891555 0.035683 0.042915<br>
Region on map: 50.241057 8.891544 0.050499 0.054932

Кто-нибудь знает, почему это происходит?

4b9b3361

Ответ 1

Проблема здесь, когда вы устанавливаете регион, уровень масштабирования карты "защелкивается" до ближайшего порога масштабирования. (Я подозреваю, что эти пороговые значения масштабирования - это количество увеличения, которое вы получаете при двойном нажатии или при нажатии двух пальцев)

Итак, если на карте отображается, например, уровень масштабирования 1, и вы устанавливаете область таким же значением диапазона: region = [mapView region]; [mapView setRegion:region]; он будет "хватать" до ближайшего уровня масштабирования выше уровня 1, то есть уровня 2, и вы будет уменьшаться примерно в два раза.

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

например.

region.span.latitudeDelta = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.latitude"] * 0.999;

region.span.longitudeDelta = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.longitude"] * 0.999;

Если пользователь увеличил двойное нажатие (и, следовательно, перешел с порога на порог), это работает очень хорошо, почти точно вернув их в один и тот же вид.

Однако, если они увеличивают масштаб изображения и вид на полпути между порогами масштабирования, он все равно выйдет на следующий уровень. В этом случае не так хорошо, но исправления пока нет.

Для этого есть явные ошибки на радаре Apple, надеюсь, он будет исправлен в будущем выпуске.

Ответ 2

У меня была та же проблема. Это очень расстраивает. Похоже, что документация для MKMapView неверна в некоторых областях, относящихся к типам данных.

Если вы зададите параметры области как (двойной), вы получите сообщение об ошибке. Однако, если параметры области пройдены (float), вы получите правильное поведение.

Итак, попробуйте

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

region.center.latitude = (float) [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.latitude"];
region.center.longitude = (float) [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.longitude"];
region.span.latitudeDelta = (float) [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.latitude"];
region.span.longitudeDelta = (float) [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.longitude"];

mapView.region = region;

Ответ 3

Хорошо, поэтому я некоторое время борюсь с этой проблемой, и я думаю, что у меня появилось эффективное обходное решение, вдохновленное теорией Круфти (MKMapView показано неправильно сохранено область). В принципе, если вы установите область отображения карты со значениями, которые вы извлекаете из своих NSUserDefaults после того, как представление карты выполнило начальную загрузку (в комплекте с поведением "отладка" ), регион карты будет тем, что вы ожидаете от него, Трюк заключается в том, чтобы найти крючок в вашем коде приложения где-то ниже по течению от инициализированного представления карты. Не очень, но он отлично работает для меня. Благодаря Crufty для понимания.

Ответ 4

Я не могу проверить, что это работает. Может ли кто-нибудь еще это сделать? Я был бы готов поспорить, что то, что вы видите, это эффект усечения ваших удвоений в поплавки. В некоторых случаях, когда это происходит со мной, я обнаружил, что могу умножить диапазон на 0.9999 и reset на регион, и тогда это будет то, что я хочу. Но не все регионы - иногда это очень разные, до 20% разные, особенно для небольших промежутков.

Ответ 5

Я нашел больший успех, используя коэффициент умножения 0,9 вместо 0,999, который он по-прежнему иногда выталкивает, но, похоже, приближается к желаемому масштабированию. По-прежнему хотелось бы решить эту проблему, просто чтобы сказать, что я ее победил! ха

Ответ 6

Постарайтесь сохранить отношение как

self.lastCameraAtitude = self.mapView.camera.altitude;

и когда u настройте свою карту

[self.mapView.camera setAltitude:self.lastCameraAtitude];

Это будет для той же самой камеры. В вашем случае u установит только область, но не камеру.

Ответ 7

Здесь быстрое расширение для правильного кодирования и декодирования MKCoordinateRegion:

extension MKCoordinateRegion {

    var encode:[String: AnyObject] {
        return ["center":
                   ["latitude": self.center.latitude,
                   "longitude": self.center.longitude],
                "span":
                   ["latitudeDelta": self.span.latitudeDelta,
                   "longitudeDelta": self.span.longitudeDelta]]
    }

    init?(decode: [String: AnyObject]) {

        guard let center = decode["center"] as? [String: AnyObject],
            let latitude = center["latitude"] as? Double,
            let longitude = center["longitude"] as? Double,
            let span = decode["span"] as? [String: AnyObject],
            let latitudeDelta = span["latitudeDelta"] as? Double,
            let longitudeDelta = span["longitudeDelta"] as? Double
        else { return nil }


        self.center = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
        self.span = MKCoordinateSpan(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta)
    }
}

Вот как это использовать:

// Save
NSUserDefaults.standardUserDefaults().setObject(mapView.region.encode, forKey: "mapRegion01")

// Restore
if let dict = NSUserDefaults.standardUserDefaults().dictionaryForKey("mapRegion01"),
    let myRegion = MKCoordinateRegion(decode: dict) {

    // do something with myRegion
}

Ответ 8

Недавно я ударил то же самое. Используя идеи из более ранних ответов, для меня работает следующая оперативная реализация 4:

override func viewWillAppear(_ animated: Bool) {
    if isMovingToParentViewController {
        setInitialRegion()
        DispatchQueue.main.asyncAfter(deadline: .now(), execute: {
            self.setInitialRegion()
        })
    }
}

Это устанавливает начальную область увеличения, когда контроллер отображения карты отображается в поле зрения. Синхронный вызов setInitialRegion установит область, привязанную к уровню масштабирования. Асинхронный вызов setInitialRegion установит точную область. Синхронный вызов по-прежнему необходим для удаления артефактов увеличения.

Ответ 9

Если вы настроили MapView в InterfaceBuilder, убедитесь, что вы этого не делаете:

_mapView = [[MKMapView alloc] init];

Как только я удалил эту строку инициализации, мое представление карты внезапно начало правильно отвечать на все обновления, которые я ему отправил. Я подозреваю, что случается, что если вы выполняете инициализацию alloc, это фактически создает другое представление, которое не отображается нигде. Тот, который вы видите на экране, является тем, который был инициализирован вашим наконечником. Но если вы назначите init новый, то что-то еще, и он ничего не собирается делать.