Comprensión de los conceptos de Canvas y Surface

114

Estoy luchando para entender el proceso de elaboración de SurfaceViewy por lo tanto el conjunto Surface/ Canvas/ Bitmapsistema, que se utiliza en Android.

He leído todos los artículos y las páginas de documentación de la API, que pude encontrar en el sitio de desarrolladores de Android, algunos tutoriales de gráficos de Android, el código fuente de LunarLander y esta pregunta .

Por favor, dígame cuáles de estas afirmaciones son verdaderas, cuáles no y por qué.

  1. Canvastiene el suyo propio Bitmap. Surfacetiene el suyo propio Canvas.
  2. Todas Viewlas ventanas comparten lo mismo Surfacey, por lo tanto, comparten lo mismo Canvas.
  3. SurfaceViewes una subclase de View, que, a diferencia de otras Viewsubclases y de Viewsí misma, tiene la suya propia Surface.

También hay una pregunta adicional:

  • ¿Por qué se necesita una Surfaceclase, si ya existe una Canvaspara operaciones de alto nivel con mapa de bits? Dé un ejemplo de una situación en la Canvasque no sea adecuado para hacer un trabajo que Surfacepueda hacer.
fyodorananiev
fuente
2
Documento de
fadden

Respuestas:

223

Aquí hay algunas definiciones:

  • Una superficie es un objeto que contiene píxeles que se componen en la pantalla. Cada ventana que ves en la pantalla (un cuadro de diálogo, tu actividad de pantalla completa, la barra de estado) tiene su propia superficie en la que se dibuja, y Surface Flinger las muestra en la pantalla final en su orden Z correcto. Por lo general, una superficie tiene más de un búfer (generalmente dos) para realizar un renderizado con doble búfer: la aplicación puede dibujar su siguiente estado de interfaz de usuario mientras el indicador de superficie está componiendo la pantalla utilizando el último búfer, sin necesidad de esperar a que finalice la aplicación. dibujo.

  • Una ventana es básicamente como piensas en una ventana en el escritorio. Tiene una única superficie en la que se renderiza el contenido de la ventana. Una aplicación interactúa con el Administrador de ventanas para crear ventanas; el Administrador de ventanas crea una superficie para cada ventana y la entrega a la aplicación para dibujar. La aplicación puede dibujar lo que quiera en Surface; para el Administrador de ventanas es solo un rectángulo opaco.

  • Una vista es un elemento de interfaz de usuario interactivo dentro de una ventana. Una ventana tiene una jerarquía de vista única adjunta, que proporciona todo el comportamiento de la ventana. Siempre que sea necesario volver a dibujar la ventana (por ejemplo, porque una vista se ha invalidado), esto se hace en la superficie de la ventana. La superficie está bloqueada, lo que devuelve un lienzo que se puede usar para dibujar en él. Se realiza un recorrido de dibujo hacia abajo en la jerarquía, pasando el lienzo hacia abajo para cada vista para dibujar su parte de la interfaz de usuario. Una vez hecho esto, Surface se desbloquea y se publica para que el búfer recién dibujado se cambie al primer plano para luego ser compuesto en la pantalla por Surface Flinger.

  • Un SurfaceView es una implementación especial de View que también crea su propia Surface dedicada para que la aplicación dibuje directamente (fuera de la jerarquía de vista normal, que de lo contrario debe compartir la superficie única de la ventana). La forma en que esto funciona es más simple de lo que podría esperar: todo lo que SurfaceView hace es pedirle al administrador de ventanas que cree una nueva ventana, indicándole que ordene en Z esa ventana inmediatamente detrás o delante de la ventana de SurfaceView, y colocándola para que coincida donde aparece SurfaceView en la ventana contenedora. Si la superficie se coloca detrás de la ventana principal (en orden Z), SurfaceView también llena su parte de la ventana principal con transparencia para que se pueda ver la superficie.

  • Un mapa de bits es solo una interfaz para algunos datos de píxeles. Los píxeles pueden ser asignados por Bitmap cuando está creando uno directamente, o puede estar apuntando a píxeles que no son de su propiedad, como lo que sucede internamente para conectar un lienzo a una superficie para dibujar. (Se crea un mapa de bits y se apunta al búfer de dibujo actual de la superficie).

También tenga en cuenta que, como esto implica, un SurfaceView es un objeto bastante pesado. Si tiene varias SurfaceViews en una interfaz de usuario en particular, deténgase y piense si esto es realmente necesario. Si tiene más de dos, es casi seguro que tenga demasiados.

hackbod
fuente
¡Muchas gracias! La respuesta aclaró las cosas. Sin embargo, parte de la conexión de Canvas a Surface no está clara. No puedo imaginar dónde se necesita tal operación. ¿Puede ser el siguiente ejemplo de esa operación: dibujar un mapa de bits en un lienzo, adquirido de SurfaceHolder con el método lockCanvas ()?
fyodorananiev
1
Así es como ocurre el dibujo Canvas es la API de dibujo 2d. Si va a dibujar sobre una superficie, necesita hacer un Canvas que apunte a su búfer para usar la API de dibujo Canvas 2d para dibujar en él.
hackbod
6
Además de #hackbod'sresponder, SurfaceViewtambién se puede renderizar desde un hilo secundario que no es posible para los Viewobjetos
Mohanraj Balasubramaniam
47

Una descripción general conceptual de Ventana, Superficie, Lienzo y Mapa de bits

A continuación, se ofrece una descripción general conceptual muy básica y sencilla de cómo se produce la interacción entre la ventana, la superficie, el lienzo y el mapa de bits.
A veces, una representación visual ayuda mucho a comprender conceptos retorcidos.
Espero que este gráfico pueda ayudar a alguien.

Sabeeh
fuente
4
Visual Las imágenes son mejores que el texto: D
Maveň ツ
18

Un mapa de bits es simplemente un contenedor para una colección de píxeles. Piense en ello como una matriz de píxeles con algunas otras funciones convenientes.

Canvas es simplemente la clase que contiene todos los métodos de dibujo. Es similar a la clase Graphics en AWT / Swing si está familiarizado con eso. Toda la lógica sobre cómo dibujar un círculo, o un cuadro, etc. está contenida dentro de Canvas. Un lienzo se basa en un mapa de bits o un contenedor GL abierto, pero no hay ninguna razón por la que en el futuro se pueda ampliar para dibujar en otros tipos de rásteres.

SurfaceView es una vista que contiene una superficie. Una superficie es similar a un mapa de bits (tiene un almacén de píxeles). No sé cómo se implementa, pero me imagino que es una especie de envoltorio de mapa de bits con métodos adicionales para cosas que están directamente relacionadas con la visualización de la pantalla (esa es la razón de una superficie, un mapa de bits es demasiado genérico). Puede obtener un lienzo de su superficie que realmente está asociando el lienzo con el mapa de bits subyacente.

Tus preguntas.

1.Canvas tiene su propio mapa de bits adjunto. Surface tiene su propio Canvas adjunto.

Sí, un lienzo funciona en un mapa de bits (o un panel GL abierto). Surface te ofrece un Canvas que funciona en cualquier Surface que esté usando para su almacén de píxeles de estilo Bitmap.

2.Todas las vistas de la ventana comparten la misma superficie y, por lo tanto, comparten el mismo lienzo.

No. Puede tener tantas vistas de superficie como desee.

3.SurfaceView es una subclase de View, que, a diferencia de otras subclases de View y View en sí, tiene su propia Superficie para dibujar.

Si. Al igual que ListView es una subclase de View que tiene su propia estructura de datos List. Cada subclase de View hace algo diferente.

sksamuel
fuente
1
Por lo tanto, Bitmapy Surfaceson sólo diferentes especies de tienda de píxeles y Canvaspuede envolver cualquiera de ellos?
fyodorananiev
2
Básicamente sí. Excepto que Canvas no puede escribir en una superficie, opera en lo que sea que Surface esté usando como su propio almacén de píxeles (sin mirar la fuente de Android, no puedo decir con certeza qué es). Probablemente sea algún tipo de extensión de mapa de bits, ya que Canvas solo proporciona constructores para mapa de bits y GL.
sksamuel
¡Gran ayuda, gracias! Acerca de la respuesta 2. En mi pregunta me refiero a vistas estándar, no a SurfaceViews. Supongamos que tengo RelativeLayout con muchos campos y botones. En este caso, ¿Surface está adjunta a toda la ventana y compartida por todas las Vistas en la jerarquía de vistas?
fyodorananiev
1
Recuerde que Surface es solo una colección de píxeles. Entonces, cada vista de superficie tiene su propia superficie y cada una se puede renderizar en una parte diferente de la pantalla. No es necesario que llenen la pantalla (aunque ese es el uso común, para representar gráficos en un juego de pantalla completa).
sksamuel
1
Realmente no pensaría en Bitmap y Surface como equivalentes. Una superficie es un objeto que Surface Flinger, el compositor de ventanas, conoce. Es decir, es algo directamente visible en la pantalla, tiene un orden Z en la pantalla, etc.
hackbod