Comprendre les concepts Canvas et Surface

114

J'ai du mal à comprendre le processus de dessin SurfaceViewet donc l'ensemble du système Surface/ Canvas/ Bitmap, qui est utilisé dans Android.

J'ai lu tous les articles et pages de documentation API, que j'ai pu trouver sur le site Android-Developers, quelques tutoriels de graphiques Android, le code source de LunarLander et cette question .

Veuillez me dire lesquelles de ces affirmations sont vraies, lesquelles ne le sont pas et pourquoi.

  1. Canvasa son propre Bitmapattaché à lui. Surfacea son propre Canvasattaché à lui.
  2. Toutes Viewles fenêtres partagent la même chose Surfaceet partagent donc la même chose Canvas.
  3. SurfaceViewest une sous-classe de View, qui, contrairement Viewaux sous-classes des autres et Viewelle - même, a la sienne Surface.

Il y a aussi une question supplémentaire:

  • Pourquoi une Surfaceclasse est-elle nécessaire , s'il existe déjà un Canvaspour les opérations de haut niveau avec bitmap. Donnez un exemple de situation où il Canvasn'est pas approprié de faire un travail qui Surfacepeut faire.
fyodorananiev
la source
2
Documentation d'
fadden

Réponses:

223

Voici quelques définitions:

  • Une surface est un objet contenant des pixels qui sont en cours de composition à l'écran. Chaque fenêtre que vous voyez à l'écran (une boîte de dialogue, votre activité en plein écran, la barre d'état) a sa propre surface dans laquelle elle dessine, et Surface Flinger les rend à l'affichage final dans leur ordre Z correct. Une surface a généralement plus d'un tampon (généralement deux) pour effectuer un rendu à double tampon: l'application peut dessiner son prochain état d'interface utilisateur pendant que le flinger de surface compose l'écran en utilisant le dernier tampon, sans avoir besoin d'attendre la fin de l'application. dessin.

  • Une fenêtre est essentiellement comme vous pensez à une fenêtre sur le bureau. Il a une seule surface dans laquelle le contenu de la fenêtre est rendu. Une application interagit avec le gestionnaire de fenêtres pour créer des fenêtres; le gestionnaire de fenêtres crée une surface pour chaque fenêtre et la donne à l'application pour le dessin. L'application peut dessiner ce qu'elle veut dans la surface; dans le gestionnaire de fenêtres, il s'agit simplement d'un rectangle opaque.

  • Une vue est un élément d'interface utilisateur interactif à l'intérieur d'une fenêtre. Une fenêtre est associée à une hiérarchie de vues unique, qui fournit tout le comportement de la fenêtre. Chaque fois que la fenêtre doit être redessinée (par exemple parce qu'une vue s'est invalidée), cela est fait dans la surface de la fenêtre. La surface est verrouillée, ce qui renvoie un canevas qui peut être utilisé pour y dessiner. Un parcours de dessin est effectué le long de la hiérarchie, ce qui permet à chaque vue de dessiner sa partie de l'interface utilisateur. Une fois cela fait, la surface est déverrouillée et affichée de sorte que le tampon qui vient d'être dessiné soit échangé au premier plan pour ensuite être composé à l'écran par Surface Flinger.

  • Un SurfaceView est une implémentation spéciale de View qui crée également sa propre surface dédiée dans laquelle l'application peut directement dessiner (en dehors de la hiérarchie de vue normale, qui doit sinon partager la surface unique pour la fenêtre). La façon dont cela fonctionne est plus simple que ce à quoi vous pourriez vous attendre - tout ce que SurfaceView fait est de demander au gestionnaire de fenêtres de créer une nouvelle fenêtre, en lui disant de commander en Z cette fenêtre immédiatement derrière ou devant la fenêtre de SurfaceView, et en la positionnant pour qu'elle corresponde où le SurfaceView apparaît dans la fenêtre contenant. Si la surface est placée derrière la fenêtre principale (dans l'ordre Z), SurfaceView remplit également sa partie de la fenêtre principale de transparence afin que la surface puisse être vue.

  • Un Bitmap n'est qu'une interface vers certaines données de pixels. Les pixels peuvent être alloués par Bitmap lui-même lorsque vous en créez un directement, ou il peut pointer vers des pixels qu'il ne possède pas, comme ce qui se passe en interne pour accrocher un canevas à une surface pour le dessin. (Un Bitmap est créé et pointe vers le tampon de dessin courant de la surface.)

Gardez également à l'esprit que, comme cela l'implique, un SurfaceView est un objet assez lourd. Si vous avez plusieurs SurfaceViews dans une interface utilisateur particulière, arrêtez-vous et demandez-vous si cela est vraiment nécessaire. Si vous en avez plus de deux, vous en avez certainement trop.

hackbod
la source
Merci beaucoup! La réponse a rendu les choses plus claires. Une partie de la connexion de Canvas à Surface n'est cependant pas claire. Je ne peux pas imaginer où une telle opération est nécessaire. Peut-on ensuite être un exemple de cette opération: dessiner un Bitmap sur un Canvas, acquis à partir de SurfaceHolder avec la méthode lockCanvas ()?
fyodorananiev
1
C'est ainsi que le dessin se produit. Canvas est l'API de dessin 2D. Si vous allez dessiner o sur une surface, vous devez créer un Canvas qui pointe vers son tampon pour utiliser l'API de dessin Canvas 2d pour y dessiner.
hackbod
6
En plus de la #hackbod'sréponse, SurfaceViewpeut également être rendu à partir d'un fil secondaire, ce qui n'est pas possible pour les Viewobjets
Mohanraj Balasubramaniam
47

Un aperçu conceptuel de Window, Surface, Canvas et Bitmap

Voici un aperçu conceptuel très basique et simple de la façon dont l'interaction se produit entre la fenêtre, la surface, le canevas et le bitmap.
Parfois, une représentation visuelle aide beaucoup à comprendre des concepts tordus.
J'espère que ce graphique pourra aider quelqu'un.

Sabeeh
la source
4
Visualy Les images valent mieux que le texte: D
Maveň ツ
18

Un Bitmap est simplement un wrapper pour une collection de pixels. Considérez-le comme un tableau de pixels avec d'autres fonctions pratiques.

Le Canvas est simplement la classe qui contient toutes les méthodes de dessin. Elle est similaire à la classe Graphics dans AWT / Swing si vous êtes familier avec cela. Toute la logique sur la façon de dessiner un cercle, une boîte, etc. est contenue dans Canvas. Un canevas dessine sur un Bitmap ou un conteneur GL ouvert, mais il n'y a aucune raison pour que dans le futur il puisse être étendu pour dessiner sur d'autres types de rasters.

SurfaceView est une vue qui contient une surface. Une surface est similaire à une image bitmap (elle possède un magasin de pixels). Je ne sais pas comment cela est implémenté mais j'imagine que c'est une sorte de wrapper Bitmap avec des méthodes supplémentaires pour les choses qui sont directement liées aux affichages d'écran (c'est la raison pour une surface, un Bitmap est trop générique). Vous pouvez obtenir un canevas de votre surface qui obtient vraiment le canevas associé au bitmap sous-jacent.

Vos questions.

1.Canvas a son propre Bitmap qui lui est attaché. Surface a son propre canevas qui lui est attaché.

Oui, un canevas fonctionne sur un Bitmap (ou un panneau GL ouvert). Surface vous donne un canevas qui fonctionne sur tout ce que Surface utilise pour son magasin de pixels de style Bitmap.

2.Toutes les vues de la fenêtre partagent la même surface et partagent donc le même canevas.

Non. Vous pouvez avoir autant de vues de surface que vous le souhaitez.

3.SurfaceView est une sous-classe de View, qui, contrairement aux autres sous-classes de View et View elle-même, a sa propre surface dans laquelle dessiner.

Oui. Tout comme ListView est une sous-classe de View qui a sa propre structure de données List. Chaque sous-classe de View fait quelque chose de différent.

sksamuel
la source
1
Alors, Bitmapet Surfaceest-ce que différentes espèces de pixels sont stockées et Canvaspeuvent emballer l'une ou l'autre?
fyodorananiev
2
En gros oui. Sauf que Canvas ne peut pas écrire sur une surface, il fonctionne sur tout ce que Surface utilise comme son propre magasin de pixels (sans regarder la source Android, je ne peux pas dire avec certitude de quoi il s'agit). C'est probablement une sorte d'extension Bitmap puisque Canvas ne fournit que des constructeurs pour Bitmap et GL.
sksamuel
Grande aide, merci! À propos de la réponse 2. Dans ma question, je parlais de vues standard, pas de SurfaceViews. Supposons que j'ai RelativeLayout avec beaucoup de champs et de boutons. Dans ce cas, Surface est-elle attachée à la fenêtre entière et partagée par toutes les vues de la hiérarchie de vues?
fyodorananiev
1
N'oubliez pas que Surface n'est qu'une collection de pixels. Ainsi, chaque vue de surface a sa propre surface et chacune peut être rendue sur une partie différente de l'écran. Ils ne remplissent pas nécessairement l'écran (bien que ce soit l'usage courant, pour rendre des graphiques sur un jeu en plein écran).
sksamuel
1
Je ne penserais vraiment pas à Bitmap et Surface comme équivalents. Une surface est un objet que le flinger de surface, le compositeur de fenêtre, connaît. C'est-à-dire que c'est quelque chose qui est directement visible sur l'écran, qui a un ordre Z sur l'écran, etc.
hackbod