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

Как определить порядок перекрытия MKAnnotationViews?

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

Можно было бы подумать, что аннотации, недавно добавленные к карте, будут заканчиваться до фронта (или, альтернативно, по крайней мере, по крайней мере), но это, похоже, не является правилом. Насколько я могу судить, я сначала создаю и добавляю ВСЕ неотъемлемые аннотации, а затем добавляю несколько недавно созданных движущихся аннотаций, но многие из них (хотя и не все!) В конечном итоге тянутся под постоянными остатками.

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

Кто-нибудь знает трюк, чтобы изменить этот странный естественный порядок аннотаций на карте? Я попытался выполнить поиск API Map Kit, но, похоже, это не говорит об этом.

4b9b3361

Ответ 1

Хорошо, поэтому для метода использования решения из MKMapViewDelegate


- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
 

В этом методе вы должны перестроить AnnotationView после его добавления в mapKit View. Таким образом, код может выглядеть так:


- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
   for (MKAnnotationView * annView in views) {
      TopBottomAnnotation * ann = (TopBottomAnnotation *) [annView annotation];
      if ([ann top]) {
         [[annView superview] bringSubviewToFront:annView];
      } else {
         [[annView superview] sendSubviewToBack:annView];
      }
   }

}

Это работает для меня.

Ответ 2

Попробуйте установить слой представления аннотаций zPosition (annotationView.layer.zPosition) в:

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views;

Ответ 3

Swift 3:

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

var count = 0 // just so we don't get the same index in bottom pins
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {  
    for view in views {
        view.layer.zPosition = CGFloat(count)
    }
    count += 1
    if count > 500 {
        count = 250 // just so we don't end up with 999999999999+ as a value for count, plus I have at least 30 pins that show at the same time and need to have lower Z-Index values than the top pins. 
    }

}

Надеюсь, что это поможет

Ответ 4

Я нахожу, что это переупорядочение представлений аннотаций вызывает всплывающее окно, когда его нажимают, чтобы он больше не был поверх всех аннотаций. Я даже попробовал доработать его так, чтобы вместо bringSubviewToFront и sendSubviewToBack я использовал insertSubview:aboveSubview и insertSubview:belowSubview:, где второй аргумент - это первый аннотационный просмотр в списке. Это, по-видимому, вызывает гораздо меньшее рассеяние спереди назад, но выходы вызова по-прежнему появляются под некоторыми аннотациями.

Ответ 5

В iOS 11 реализация displayPriority сломала все решения, которые используют bringSubviewToFront или zPosition.

Если вы переопределяете CALayer представления аннотаций, вы можете бороться с zposition обратно из ОС.

class AnnotationView: MKAnnotationView {

    /// Override the layer factory for this class to return a custom CALayer class
    override class var layerClass: AnyClass {
        return ZPositionableLayer.self
    }

    /// convenience accessor for setting zPosition
    var stickyZPosition: CGFloat {
        get {
            return (self.layer as! ZPositionableLayer).stickyZPosition
        }
        set {
            (self.layer as! ZPositionableLayer).stickyZPosition = newValue
        }
    }

    /// force the pin to the front of the z-ordering in the map view
   func bringViewToFront() {
        superview?.bringSubview(toFront: self)
        stickyZPosition = CGFloat(1)
    }

    /// force the pin to the back of the z-ordering in the map view
   func setViewToDefaultZOrder() {
        stickyZPosition = CGFloat(0)
    }

}

/// iOS 11 automagically manages the CALayer zPosition, which breaks manual z-ordering.
/// This subclass just throws away any values which the OS sets for zPosition, and provides
/// a specialized accessor for setting the zPosition
private class ZPositionableLayer: CALayer {

    /// no-op accessor for setting the zPosition
    override var zPosition: CGFloat {
        get {
            return super.zPosition
        }
        set {
            // do nothing
        }
    }

    /// specialized accessor for setting the zPosition
    var stickyZPosition: CGFloat {
        get {
            return super.zPosition
        }
        set {
            super.zPosition = newValue
        }
    }
}

Ответ 6

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

Окончательное, хорошо выполненное решение не было таким тривиальным, поэтому я просто опишу шаги, которые я сделал здесь. Заказ аннотаций, который использует MKMapView, не учитывает добавленный порядок или даже порядок свойства overriden annotations. Так что...


Действия

• Создайте CADisplayLink
• Каждый кадр, переупорядочивает аннотации, используя как слой zPosition, так и порядок представления в массиве superiew subviews.
• Если выбран вид, продвиньте его на передний план в своей схеме заказа
• Нажатие на аннотации по-прежнему учитывает внутренний MKMapView порядок, несмотря на уже внесенные изменения. Чтобы отменить это, добавьте MKMapViewDelegate
• В методе делегата object mapView:didSelect: проверьте, выбрана ли выбранная аннотация, как вы хотите ее использовать. • Вы можете определить правильную/приоритетную аннотацию, выполнив тесты на аннотации самостоятельно, с учетом вашего собственного заказа.
• Если выбранная аннотация правильная, отлично. Если нет, вручную выберите правильную аннотацию, используя selectAnnotation:animated:


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