2012-04-04 4 views
7

Ich implementiere ein einfaches iOS-Solitaire-Spiel, das es dem Benutzer erlaubt, die Karten auf die übliche Weise herumzuziehen. Die Karten werden mit der UIView Unterklasse CardView dargestellt. Alle Kartenansichten sind Geschwister, die Unteransichten von SolitaireView sind. Der folgende Ausschnitt versucht, „eine Karte an die Front zu bringen“, so dass es vor allem der anderen Ansichten ist, wie es gezogen wird:UIView bringSubviewToFront: bringt * keine * Sicht nach vorne

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    UITouch *touch = [touches anyObject]; 
    if (touch.view.tag == CARD_TAG) { 
     CardView *cardView = (CardView*) touch.view; 
     ... 
     [self bringSubviewToFront:cardView]; 
     ... 
    } 
} 

Leider bleibt die Karte der Z-Reihenfolge während des Drag unverändert. In den Bildern unten ziehe ich den König. Beachten Sie, wie es richtig oben ist die Neun im linken Bild, ist aber falsch unter den Zwei (unter dem gesamten Stapel tatsächlich) im rechten Bild:

enter image description hereenter image description here

Ich habe auch versucht, verändern die layer.zPosition Eigenschaft als gut vergebens. Wie kann ich die Kartenansicht beim Ziehen nach vorne bringen? Ich bin verwirrt.

+0

Ich entdeckte, dass 'bringSubviewToFront:' die ‚needsLayout‘ Flag Ansicht Trigger festgelegt werden. Meine 'layoutSubviews' Methode rief auch' bringSubviewToFront: 'auf und löschte so alle View z-Befehle in ihren ursprünglichen Zustand zurück! – wcochran

+0

Dann ist die Lösung dafür? Ich habe auch die gleiche Art von Anforderungen, wo aus der Liste der Karten, wenn ich irgendeine der mittleren Ordnung Karte auswählen, sollte es kommen, dann nach vorne kommen. aber meine Animation funktioniert nicht wegen bringSubviewToFront: Methode – Mrunal

+0

Wenn Sie bei der Verwendung von UIView-Unterklassen bleiben, dann müssen Sie die gezogene Karte markieren, damit layoutSubviews sie oben platzieren kann. Ich habe tatsächlich auf CALayers wie unten erwähnt umgeschaltet. – wcochran

Antwort

8

Bestätigt. bringSubviewToFront: bewirkt, dass layoutSubview aufgerufen wird. Da meine Version von layoutSubviews die z-Aufträge in allen Ansichten festlegt, wurde dadurch die z-Reihenfolge rückgängig gemacht, die ich im obigen Code touchesBegan:withEvent eingestellt hatte. Apple sollte diesen Nebeneffekt in der bringSubviewToFront Dokumentation erwähnen.

Anstatt eine UIView Unterklasse zu verwenden, habe ich eine CALayer Unterklasse namens CardLayer erstellt. Ich handle die Berührung in meiner KlondikeView Unterklasse wie unten aufgeführt. topZPosition ist eine Instanzvariable, die die höchste zPosition aller Karten verfolgt. Beachten Sie, dass Modifikation wird die zPosition in der Regel animiert - ich diese drehen unten im Code ab:

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { 
    UITouch *touch = [touches anyObject]; 
    CGPoint touchPoint = [touch locationInView:self]; 
    CGPoint hitTestPoint = [self.layer convertPoint:touchPoint 
              toLayer:self.layer.superlayer]; 
    CALayer *layer = [self.layer hitTest:hitTestPoint]; 

    if (layer == nil) return; 

    if ([layer.name isEqual:@"card"]) { 
    CardLayer *cardLayer = (CardLayer*) layer; 
    Card *card = cardLayer.card; 

    if ([self.solitaire isCardFaceUp:card]) { 
     //...                            
     [CATransaction begin]; // disable animation of z change                 
     [CATransaction setValue:(id)kCFBooleanTrue 
         forKey:kCATransactionDisableActions];    
     cardLayer.zPosition = topZPosition++; // bring to highest z 

     // ... if card fan, bring whole fan to top 

     [CATransaction commit]; 
     //...                            
    } 
    // ...                            
    } 

} 
+4

Ich denke, mit 'UIView's für das Spiel Karten möglicherweise eine schlechte Design-Wahl gewesen sein - ich glaube nicht, dass sie wirklich beabsichtigt waren dafür. Ich denke, ich werde zurücktreten und stattdessen "CALayer" benutzen. – wcochran