2010-05-20 1 views
30

J'ai une super vue, qui a 2 vues. Ces sous-vues sont superposées.Comment faire un NSView passer à l'avant de tous les NSViews

Chaque fois que je choisis une vue dans un menu, la vue correspondante doit devenir la vue de face et les actions de poignée. C'est-à-dire qu'il devrait s'agir de la sous-vue la plus frontale.

acceptsFirstResponder démissionne tout fonctionne bien. Mais les événements de souris vers le bas sont envoyés à la sous-vue la plus haute qui a été définie.

Cordialement, Dhana

+0

Garde-toi: "Note: Pour des raisons de performance, de cacao n'applique pas clipping entre frères et soeurs vues ..." Et de plus! "Le cacao ne garantit pas le bon comportement d'invalidation et de dessin lorsque les vues de frères et sœurs se chevauchent." Comme il est dit dans le manuel:" Si vous voulez qu'une vue soit dessinée devant une autre vue, vous devez faire de la vue de face une vue secondaire (ou descendante) de la vue arrière. " Guide dans le doco OSX) – Fattie

Répondre

35

Voici une autre façon d'y arriver qui est un peu plus claire et succincte:

[viewToBeMadeForemost removeFromSuperview]; 
[self addSubview:viewToBeMadeForemost positioned:NSWindowAbove relativeTo:nil]; 

par la documentation pour cette méthode, lorsque vous utilisez relativeTo:nil la vue est ajoutée ci-dessus (ou ci-dessous, avec NSWindowBelow) tous ses frères et sœurs.

+3

Il existe un problème avec l'approche ci-dessus: lorsque vous envoyez ** removeFromSuperview ** à une vue, celle-ci est libérée: vous devez d'abord conserver l'affichage, puis rééquilibrer Deuxièmement, vous devez supprimer et ajouter la vue à la hiérarchie (ce qui peut être coûteux en fonction de la complexité de votre vue hierarc hy). Il existe une autre méthode qui évite d'avoir à supprimer et à ajouter des vues de la hiérarchie de vue à l'aide de la fonction de tri de sous-vue intégrée de NSView. Voir ci-dessous. – Dalmazio

+0

Je pense que les deux lignes de code sont toujours dans la même boucle d'événements, donc viewToBeMadeForemost ne sera pas publié avant la deuxième ligne. –

+0

@LiFumin, c'est incorrect. Vous supposez que removeFromSuperview libère la vue, ou qu'un autre code l'a libérée. De la doc pour -removeFromSuperview: "La vue est également libérée, si vous prévoyez de la réutiliser, assurez-vous de la conserver avant d'envoyer ce message et de la relâcher comme il convient en l'ajoutant comme sous-vue d'un autre NSView." Dalmazio a raison, la vue doit être conservée. Cette solution a aussi des problèmes concernant la rupture des contraintes, etc., j'imagine. Cela ne devrait pas être la réponse acceptée. – bhaller

1

Ci-dessous le code donné devrait fonctionner correctement ..

NSMutableArray *subvies = [NSMutableArray arrayWithArray:[self subviews]];//Get all subviews.. 

    [viewToBeMadeForemost retain]; //Retain the view to be made top view.. 

    [subvies removeObject:viewToBeMadeForemost];//remove it from array 

    [subvies addObject:viewToBeMadeForemost];//add as last item 

    [self setSubviews:subvies];//set the new array.. 
+0

Sauf si vous utilisez ARC ... – geowar

+0

Cela devrait être la réponse acceptée, car il est plus proche d'être correct que les autres.Toutefois, notez qu'il devrait faire une version de [viewToBeMadeForemost], à la fin, sinon – bhaller

11

Une autre méthode consiste à utiliser la méthode sortSubviewsUsingFunction: context: de NSView pour réorganiser une collection de vues de frères et soeurs à votre convenance. Par exemple, définir votre fonction de comparaison:

static NSComparisonResult myCustomViewAboveSiblingViewsComparator(NSView * view1, NSView * view2, void * context) 
{  
    if ([view1 isKindOfClass:[MyCustomView class]])  
     return NSOrderedDescending;  
    else if ([view2 isKindOfClass:[MyCustomView class]])  
     return NSOrderedAscending;  

    return NSOrderedSame; 
} 

Ensuite, lorsque vous voulez vous assurer que votre vue personnalisée reste au-dessus de toutes les vues frères et soeurs, envoyer ce message à votre superview de vue personnalisée:

[[myCustomView superview] sortSubviewsUsingFunction:myCustomViewAboveSiblingViewsComparator context:NULL]; 

Vous pouvez déplacez ce code dans la vue d'ensemble elle-même et envoyez le message sortSubviewsUsingFunction: context: à à la place de.

+2

@Jonathan. C'est pour les UIViews qui font partie du framework iOS. La question concerne les NSViews utilisés pour les applications OS X. – Mathias

+0

Cela fonctionne, mais semble rendre l'ordre du reste des sous-vues au hasard, puisque le doc dit "NSOrderedSame si leur commande n'est pas importante". Une solution qui préserve l'ordre du reste des vues serait beaucoup mieux. En outre, l'utilisation de IsKindOfClass: ici est étrange; la question n'indique pas que les sous-classes de vues personnalisées sont utilisées, ou que les sous-vues de frères et sœurs à réorganiser sont des classes différentes. – bhaller

-10

Vous pouvez essayer ceci:

[viewToBeMadeFirst.window makeKeyAndOrderFront:nil]; 
+0

oui, celui-ci fonctionne pour moi: [self.window makeKeyAndOrderFront: self]; –

+8

Nous parlons de NSView, pas NSWindow – NSAddict

4

J'ai pu obtenir ce travail sans appeler removeFromSuperView

// pop to top 
[self addSubview:viewToBeMadeForemost positioned:NSWindowAbove relativeTo:nil]; 
+0

Est-ce que cela crée une nouvelle vue plutôt que d'utiliser la vue existante? – Krishnabhadra

+1

Cela a causé l'application à pendre pour toujours. –

+0

Si cela fonctionne, c'est juste par accident; les docs ne garantissent pas le comportement d'ajout d'une vue déjà ajoutée. – bhaller

1

Vous pouvez y parvenir en ajoutant simplement à nouveau la vue; il ne créera pas une autre instance de celui-ci.

[self addSubview:viewToBeMadeForemost]; 

Vous pouvez enregistrer le nombre de sous-vues avant et après l'exécution de cette ligne de code.

+1

Si cela fonctionne, c'est juste par accident; les docs ne garantissent pas le comportement d'ajout d'une vue déjà ajoutée. – bhaller

0

Pour déplacer une vue vers l'avant, elle doit être placée comme dernier élément dans le tableau des sous-vues. Voici une solution 3.0 Swift:

func bringChildToFrontWith(viewIdentifier: Int) { 
    var subViewArray = self.subviews // Apple docs recommend copying subViews array before operating on it, as it "can be changed at any time" 
    for ix in 0 ..< subViewArray.count { 
     if let childView = subViewArray[ix] as? MyViewSubClass { 
      if childView.myViewSubClassIdentifier == viewIdentifier { 
       let topItem = subViewArray[ix]; 
       subViewArray.remove(at: ix) 
       subViewArray.append(topItem) 
       self.contentView.subviews = subViewArray 
      } 
     } 
    } 
} 
Questions connexes