2009-08-22 5 views
0

J'ai une sous-classe NSView qui peut être déplacée dans sa vue d'ensemble. Je déplace les vues en appelant les méthodes setFrameOrigin et setFrameRotation de NSView dans mon gestionnaire d'événements mouseDragged. Les vues sont à la fois déplacées et pivotées à chaque appel.NSView laisse des artefacts sur un autre NSView lorsque le premier est déplacé sur le second

J'ai plusieurs instances de ces vues contenues par une seule super-vue. Le problème que j'ai est que, comme une vue est traînée au-dessus d'une autre, elle laisse derrière elle des artefacts sur la vue qu'elle éclipse. J'ai enregistré a short video de cela en action. Malheureusement, en raison de la compression vidéo, les artefacts ne sont pas très visibles.

Je soupçonne fortement que cela est lié à la traduction simultanée et à la rotation. Quartz Debug révèle qu'un rectangle de la vue occluding (ou occluded) est mis à jour lorsqu'une autre vue est traînée à travers (video here); en quelque sorte ce rectangle est mal calculé par le moteur de dessin, donc une partie de la vue qui devrait être redessinée n'est pas.

Le kicker est je n'ai aucune idée comment résoudre ce problème. Je ne trouve aucun moyen de spécifier manuellement le rectangle de mise à jour dans les documents, et je ne suis pas sûr que ce soit ce qui doit arriver. Des idées? Merci!

Répondre

1

Vous pouvez également envisager d'utiliser CALayers au lieu de vues. Contrairement aux vues, les couches sont destinées à être empilées avec leurs frères et sœurs.

Pour une solution de moindre effort possible, essayez de faire en sorte que les vues soient protégées par une couche; il peut ou non résoudre ce problème, mais ça vaut le coup d'essayer.

+0

Cette solution me plaît parce que j'avais voulu utiliser Core Animation pour animer certaines choses que ces vues font (comme se déplacer quand une autre vue est glissée sur le même slot). Malheureusement, le simple fait de donner une couche aux vues ne résout pas le problème (en fait, dessiner sur cette couche pourrait faire l'affaire). Si je devais utiliser un CALayer au lieu d'une vue, comment pourrais-je réagir aux événements? CALayers n'hérite pas de NSRespnder. (Désolé, je suis un Cocoa n00b et fondamentalement aucune idée sur Core Animation.) –

+0

Ma compréhension est que vous avez besoin d'au moins une vue à un certain niveau, même si c'est une seule vue d'hébergement et de contrôle de la hiérarchie de la couche entière. Dans cet arrangement, la vue gérerait les événements, en utilisant des messages tels que 'hitTest:' pour déterminer avec quelles couches l'utilisateur travaille. –

+0

Il s'avère que je le faisais mal. Une fois que j'ai appelé la méthode appropriée pour donner à mes vues (créées par programmation) un support CALayer, les artefacts ont disparu. Bien sûr, mon positionnement et ma rotation ont été brisés, mais ce n'est pas la question à résoudre. Merci pour la suggestion! –

0

Les vues ne sont pas vraiment conçues pour être empilées de manière interactive. Peut être fait, mais les cas de bord abondent.

Généralement, pour ce genre de chose, vous utiliseriez une infrastructure de type cellule si vous voulez faire glisser en vue (voir l'exemple de Sketch) et vous utiliseriez l'infrastructure de glisser-déposer si vous voulez faire glisser entre vues ou fenêtres (ou applications).

Si vous voulez vraiment faire glisser une vue transformée par-dessus, vous devez invalider un rectangle de la vue sous la vue en train d'être déplacée. Le rectangle devra être plus grand de quelques pixels que la surface totale (non-traitée/non-transformée) qui est masquée par la vue en train d'être déplacée. Les artefacts sont, effectivement, causés par une erreur d'arrondi; les lignes diagonales ne sont qu'une estimation sur un système de dessin raster.

Voir la méthode:

- (void)setNeedsDisplayInRect:(NSRect)invalidRect; 
Questions connexes