Hoe kan ik de volgorde van overlappende MKAnnotationViews definiëren?

stemmen
29

Ik heb verschillende MKAnnotations (en de bijbehorende views) in mijn kaart, en het wordt soms echt druk. Nu, de aantekeningen in mijn app zijn er in twee smaken: sommige zijn gebonden om te blijven waar ze zijn, terwijl anderen zal bewegen naarmate de tijd vordert. Ik zou de voorkeur aan de meer stabiele die visueel op de achtergrond en de bewegende die moeten altijd passeren in de voorkant van hen.

Men zou denken, misschien dat de annotaties meest recent toegevoegde om de kaart zou eindigen aan de voorzijde (of als alternatief aan de achterkant, in ieder geval), maar dit schijnt niet enkel op de regel. Voor zover ik kan vertellen, ik maak en voeg alle niet-bewegende annotaties eerste, en voeg dan wat nieuw geïnstantieerd bewegende annotaties, maar velen van hen (hoewel niet alle!) Uiteindelijk uit in het kader van de voortdurend stokstijf degenen.

Interessant is dat wanneer de tijd verstrijkt, en toch nieuwe bewegende annotaties worden gemaakt, hebben ze de neiging om meer naar de top dan de eerste die aangetrokken - zelfs als alle bewegende annotatie objecten zijn gemaakt nadat de niet-bewegende onderdelen al aan de kaart toegevoegd.

Heeft iemand een truc om deze vreemde natuurlijke orde van het uitzicht aantekening op de kaart te veranderen weten? Ik heb geprobeerd om de kaart Kit API te zoeken, maar het lijkt niet te spreken van zoiets.

De vraag is gesteld op 17/07/2009 om 20:33
bron van user
In andere talen...                            


7 antwoorden

stemmen
38

Ok, dus voor oplossing gebruik van werkwijze MKMapViewDelegate


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

Bij deze methode moet u AnnotationView herschikken, nadat zij tot mapKit View werd toegevoegd. Dus, code mei ziet er als volgt uit:


- (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];
      }
   }

}

Dit werkt voor mij.

antwoordde op 31/07/2009 om 17:09
bron van user

stemmen
11

Probeer zPosition setup annotatie view laag's (annotationView.layer.zPosition) in:

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views;
antwoordde op 03/05/2013 om 11:40
bron van user

stemmen
4

Swift 3:

Ik krijg pin locaties uit API en ik was met soortgelijke kwesties, de pinnen die moest worden op de top waren niet. Ik was in staat om het op te lossen als deze.

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

}

Ik hoop dat dit helpt

antwoordde op 05/12/2016 om 21:06
bron van user

stemmen
3

Onder iOS 11 de uitvoering van displayPrioritybrak alle oplossingen die gebruik maken van bringSubviewToFrontof zPosition.

Als u de aantekening standpunt van CALayer overschrijven, kunt u de controle over zPosition worstelen terug van het OS.

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
        }
    }
}
antwoordde op 25/01/2018 om 23:23
bron van user

stemmen
2

Ik vind dat dit het herordenen van het uitzicht annotatie zorgt ervoor dat het bijschrift dat verschijnt wanneer men geklikt om niet langer op de top van alle annotaties. Ik heb zelfs geprobeerd het verfijnen van het zo dat in plaats van bringSubviewToFronten sendSubviewToBack, ik gebruik insertSubview:aboveSubviewen insertSubview:belowSubview:waar de tweede argument is de eerste annotationView in de lijst. Dit lijkt veel minder voor zorgen om een back-verstrooiing, maar de oproep outs pop nog steeds onder sommige annotaties.

antwoordde op 05/11/2009 om 15:21
bron van user

stemmen
1

In de gemachtigde functie kunt u de pin te forceren op de top te selecteren:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?` {
    ...
    if my annotation is the special one {
        annotationView.isSelected = true
    }
    ...
}
antwoordde op 18/02/2019 om 01:32
bron van user

stemmen
0

Ik echt nodig om dit te doen, en geen van de (huidige) antwoorden leek een betrouwbare uitvoering te bereiken. Ze soort werkte, maar panning de kaart, het selecteren van aantekeningen, of inzoomen kon verpesten de bestelling opnieuw.

De finale, goed gedragen oplossing was niet zo triviaal, dus ik zal gewoon een overzicht van de stappen die ik nam hier. De annotatie bestellen die MKMapViewgebruikt niet de toegevoegde orde, of zelfs de volgorde van een overschreven respecteren annotationseigendom. Zo...


Stappen

• Maak een CADisplayLink
• Elk beeld, de volgorde aantekeningen met behulp van zowel de laag zPosition, en de sortering in de superview van het standpunt van het subviewsarray.
• Als de weergave wordt gekozen, het bevorderen van het aan het front in uw bestelling schema
• Tikken op annotaties nog interne respecteert MKMapViewbestellen, ondanks de reeds gemaakte wijzigingen. Om dit tegen te gaan, voegt u een MKMapViewDelegate
• In de gedelegeerde object mapView:didSelect:methode, controleer dan of de geselecteerde annotatie is wat je zou willen zijn
• U kunt achterhalen van de juiste / prioriteit annotatie door het uitvoeren hit tests van de annotaties zelf, met uw eigen bestelling rekening gehouden met
• Als de geselecteerde annotatie is correct, geweldig. Zo niet, de juiste annotatie handmatig te selecteren met behulp vanselectAnnotation:animated:


En daar heb je het. De bovenstaande methode lijkt goed te werken, en de prestaties hit van het uitvoeren van dit elk frame is niet zo slecht. Je zou ook kijken naar de overstap naar MapBox, waarvan ik denk ondersteunt annotatie bestellen, maar dit is niet altijd een optie om verschillende redenen.

antwoordde op 15/09/2017 om 01:54
bron van user

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more