32 votes

Quartz 2D méthode drawRect (iPhone)

J'ai 4 iPhone/Cacao/Core Animation/Objective-C livres en face de moi, avec de nombreux exemples de code à partir du web. Et pourtant, j'ai toujours l'impression que je vais manquer une compréhension fondamentale de la façon dont le dessin fonctionne en Quartz 2D.

Est - drawRect() veut tout simplement être un crochet dans lequel exécuter votre code de dessin? Ou est-ce la méthode censé également redessiner les régions qui sont "endommagé", et ont besoin d'être repeints? Puis-je tirer mon truc une fois et ensuite il "colle", ou dois-je repeindre l'ensemble de la scène à tout moment via drawRect()? Java est Graphics2D objet fonctionne de cette façon - vous devez dessiner l'ensemble de votre "image" à chaque fois que paint() est appelée, de sorte que vous devez être prêt à re-construire, à tout moment (ou cache).

Comment voulez-vous mettre en œuvre un simple programme de dessin? Auriez-vous à "rappeler" chaque ligne/point/trait que l'utilisateur a attiré, et de répliquer à chaque fois drawRect() est appelé? Comment à propos de "offscreen" rendu; pouvez-vous faire à tous de votre dessin, puis en appel en [self setNeedsDisplay] d'avoir de vos écritures affichée à l'écran?

Disons que, en réponse à un toucher de l'utilisateur, je veux mettre un "X" sur l'écran où il a touché jusqu'. Le X doit y rester, et chaque toucher de nouveaux produit une autre X. Dois-je rappeler de tous ces retouche coordonnées puis de les dessiner tous, en drawRect() ?

EDIT:

À moins que j'ai mal compris, joconor et Hector Ramos réponses ci-dessous sont contredire les uns les autres. Et c'est une bonne démonstration de ma confusion à ce sujet. :-)

38voto

Brad Larson Points 122629

Une partie de la confusion entre les différents Cacao références provient de l'introduction de la couche adossés à des points de vue dans Leopard. Sur l'iPhone, tous les UIViews de couche-backed, où dans Leopard vues devez activer manuellement la couche de support.

Pour une couche adossés à vue, le contenu est tiré une fois en utilisant ce que vous avez fournies en drawRect(), mais puis est mis en mémoire tampon dans la couche. La couche agit comme un rectangulaire de texture, de sorte que lorsque vous déplacez le calque adossés à vue ou de la couvrir, pas de redessiner est nécessaire, la texture est juste déplacé à l'emplacement via le GPU. Sauf si vous définissez l' needsDisplayOnBoundsChange property de YES pour les couches, en changeant la taille de la couche (ou de son contenant vue) va tout simplement à l'échelle le contenu. Cela peut conduire à l'floue graphiques au sein de votre point de vue ou de la couche, de sorte que vous voudrez peut-être forcer un renouvellement dans ce cas. setNeedsDisplay sera le déclencheur d'un manuel de redessiner de la vue ou de la couche de contenu, et, ultérieurement, de recaching de ce contenu dans la couche.

Pour des performances optimales, il est conseillé d'éviter d'avoir des appels fréquents drawRect, en raison de Quartz de dessin et de recaching dans une couche sont des opérations coûteuses. Il est préférable d'essayer de faire une animation à l'aide des calques distincts que vous pouvez vous déplacer ou mettre à l'échelle.

La base de Cacao références que vous avez vu qui concernent le bureau peut supposer la non-couche adossés à des points de vue, qui font appel drawRect: de tout temps, la vue doit être mis à jour, si c'est à partir de circulation, de mise à l'échelle, ou d'avoir une partie de la vue obscurcie. Comme je l'ai dit, tous les UIViews de couche-backed, donc ce n'est pas le cas sur l'iPhone.

Cela dit, pour votre application de dessin, une façon de le faire serait de maintenir un tableau d'objets dessinés et appel drawRect: chaque fois que l'utilisateur ajoute quelque chose de nouveau, une itération sur chaque auparavant établi les objets dans l'ordre. Je pourrais en proposer une autre approche de l'endroit où vous créez un nouveau UIView ou CALayer pour chaque opération de dessin. Le contenu de cette opération de dessin (ligne, arc, X, etc.) serait attiré par l'individu de la vue ou de la couche. De cette façon, vous n'aurez pas à redessiner tout sur une nouvelle touche, et vous pourriez être en mesure de faire bien vecteur de style de montage par déplacement de chacun des éléments dessinés autour indépendamment des autres. Pour des dessins complexes, il pourrait y avoir un peu de mémoire compromis dans cette affaire, mais je serais prêt à parier qu'il aurait beaucoup mieux les performances d'affichage minimale (utilisation du PROCESSEUR et de scintillement).

4voto

Hector Ramos Points 4810

drawRect() dessine à l'écran de la mémoire tampon. Vous n'avez pas besoin de redessiner tout temps, les régions sont "endommagé" perse, comme l'iPhone OS prend en charge la superposition des points de vue. Il vous suffit d'écrire une fois pour le tampon, et de laisser le système d'exploitation gérer le reste. Ce n'est pas comme les autres environnements de programmation où vous avez besoin de garder redessiner à chaque fois que quelque chose passe au-dessus de votre point de vue.

2voto

Jay O'Conor Points 1911

Toujours être prêt pour dessiner la zone appropriée de votre point de vue lorsque drawRect: est appelé.

Bien que le système puisse tampon de votre point de vue, qui ne pourront éviter drawRect: d'être appelé. Si pour une raison quelconque, le système a pour effet d'invalider la mémoire tampon, votre drawRect: méthode peut être invoqué à nouveau. Aussi, drawRect: sera invoqué pour les différents domaines de votre point de vue comme ils deviennent visibles comme un résultat de défilement et d'autres opérations qui influent sur la visibilité des zones de votre point de vue.

2voto

justin Points 72871

Est drawRect() destinée à être simplement un crochet dans lequel exécuter votre code de dessin?

Il est destiné à redessiner la région (rect) qui est transmis à vous, à l'aide de l'actuel contexte graphique de la pile. Pas plus.

Ou est-ce la méthode censé également redessiner les régions qui sont "endommagé", et ont besoin d'être repeints?

Pas de. Si elle est sale régions ne se chevauchent pas, vous pouvez recevoir plusieurs appels d' drawRect: avec les différents rectangles passé à vous. Rectangles sont invalidées à l'aide de setNeedsDisplayInRect:. Si seulement une partie de votre point de vue de la surface doit être redessiné, puis il vous sera demandé de dessiner la partie quand il est temps de dessiner.

Puis-je tirer mon truc une fois et ensuite il "colle", ou dois-je repeindre l'ensemble de la scène à tout moment via drawRect()?

Il ne fait pas un "bâton". Rects devenir invalidé au cours de votre application d'exécution, et vous êtes prié de redessiner ces rectangles lorsque le point de vue des besoins du système de mise à jour de l'écran. Vous repeindre uniquement le rectangle qui est demandé.

Dans certains cas, une simple mise en œuvre peut (plutôt paresseusement) invalider le point de vue de l'ensemble de l'rect à chaque fois une partie est invalidé. C'est généralement mauvaise, parce qu'elle nécessite généralement plus de dessin que ce qui est nécessaire, et est particulièrement de gaspillage lorsque les vues ne sont pas opaques.

Java est Graphics2D objet fonctionne de cette façon - vous devez dessiner l'ensemble de votre "image" à chaque fois que paint() est appelée, de sorte que vous devez être prêt à re-construire, à tout moment (ou cache).

Pas avec AppKit ou UIKit.

Comment voulez-vous mettre en œuvre un simple programme de dessin? Auriez-vous à "rappeler" chaque ligne/point/trait que l'utilisateur a attiré, et de répliquer à chaque fois drawRect() est appelée?

Vous devrez vous rappeler le contexte (par exemple, chaque ligne/point/trait) nécessaires pour attirer votre point de vue. Vous avez seulement besoin d'attirer la région qui est demandé. Techniquement, le système graphique ne serait pas vous plaindre si vous deviez dessiner en dehors de cette rect, mais qui pourrait conduire à des artefacts.

Pour un rendu complexe, il peut être plus facile ou plus efficace pour attirer l'extérieur de la mémoire tampon (par exemple, bitmap), puis de l'utiliser que prerendered représentation bitmap pour obtenir les choses à l'écran, tandis que dans drawrect:. (voir aussi sa réponse pour les couches)

Comment à propos de "offscreen" rendu; pouvez-vous faire à tous de votre dessin, puis en appel [auto setNeedsDisplay] d'avoir de vos écritures affichée à l'écran?

Oui, vous pouvez le faire. Plus précisément, vous rendre à un tampon (par exemple, une image bitmap), lorsque vous avez terminé le rendu de l'image bitmap, la nullité de l'rect vous souhaitez insérer, puis de dessiner à l'écran en utilisant les données de l'image lorsque drawRect: est appelé.

Disons que, en réponse à un toucher de l'utilisateur, je veux mettre un "X" sur l'écran où il a touché jusqu'. Le X doit y rester, et chaque toucher de nouveaux produit une autre X. Dois-je rappeler de tous ces retouche coordonnées et ensuite en tirer tous dans drawRect() ?

Eh bien, vous avez quelques options. Votre proposition est l'un (en supposant que vous dessinez à l'intérieur de l'rect passé à vous). Une autre serait de créer un "X", de la vue, et il suffit de rappeler les points nécessaires à la reconstruction de la vue si vous avez besoin de ces Xs pour conserver sur lance. Dans de nombreux cas, vous pouvez facilement diviser des problèmes complexes dans des couches (simple jeu en 2D):

  • 1) L'image de fond avec l'horizon.
  • 2) Certaines choses dans le premier plan qui ne changent pas souvent.
  • 3) Le personnage que le joueur utilise l'utilisateur de naviguer à travers le jeu.

Ainsi, la plupart des problèmes peuvent être facilement divisé de sorte que vous n'avez pas à rendre tout tout le temps. Cela réduit la complexité et améliore les performances si bien fait. Si fait mal, elle peut être de plusieurs bien pire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X