Понимание концепций Canvas и Surface

114

Я изо всех сил пытаюсь понять процесс рисования SurfaceViewи, следовательно, всю систему Surface/ Canvas/ Bitmap, которая используется в Android.

Я прочитал все статьи и страницы документации API, которые мне удалось найти на сайте разработчиков Android, несколько руководств по графике для Android, исходный код LunarLander и этот вопрос .

Скажите, пожалуйста, какие из этих утверждений верны, а какие нет и почему.

  1. CanvasBitmapк нему прикреплено собственное . к нему прикреплено Surfaceсобственное Canvas.
  2. Все Viewокна используют одно Surfaceи то же и, следовательно, используют одно и то же Canvas.
  3. SurfaceViewявляется подклассом View, который, в отличие от других Viewподклассов и Viewсамого себя, имеет свой собственный Surface.

Есть еще один дополнительный вопрос:

  • Зачем нужен Surfaceкласс, если он уже есть Canvasдля высокоуровневых операций с битовой картой. Приведите пример ситуации, когда Canvasне подходит для выполнения работы, которую Surfaceможно выполнять.
fyodorananiev
источник

Ответы:

223

Вот несколько определений:

  • Поверхность - это объект, содержащий пиксели, которые накладываются на экран. Каждое окно, которое вы видите на экране (диалоговое окно, ваше полноэкранное действие, строка состояния), имеет свою собственную поверхность, на которую оно обращается, и Surface Flinger отображает их на окончательном дисплее в их правильном Z-порядке. Поверхность обычно имеет более одного буфера (обычно два) для рендеринга с двойной буферизацией: приложение может рисовать свое следующее состояние пользовательского интерфейса, в то время как отражатель поверхности составляет экран, используя последний буфер, без необходимости дожидаться завершения работы приложения. Рисунок.

  • Окно в основном похоже на окно на рабочем столе. Он имеет единственную поверхность, на которой отображается содержимое окна. Приложение взаимодействует с диспетчером окон для создания окон; Диспетчер окон создает поверхность для каждого окна и передает ее приложению для рисования. Приложение может рисовать на поверхности все, что угодно; для оконного менеджера это просто непрозрачный прямоугольник.

  • Представление - это интерактивный элемент пользовательского интерфейса внутри окна. Окно имеет прикрепленную к нему единую иерархию представлений, которая обеспечивает все поведение окна. Всякий раз, когда окно необходимо перерисовать (например, из-за того, что представление стало недействительным), это делается на поверхности окна. Поверхность заблокирована, что возвращает Canvas, который можно использовать для рисования на ней. Обход отрисовки выполняется вниз по иерархии, передавая Canvas вниз для каждого представления, чтобы отрисовать его часть пользовательского интерфейса. После этого Surface разблокируется и публикуется, так что только что нарисованный буфер перемещается на передний план, чтобы затем его компоновали на экран с помощью Surface Flinger.

  • SurfaceView - это специальная реализация View, которая также создает свою собственную выделенную поверхность для непосредственного рисования приложением (за пределами обычной иерархии представлений, которая в противном случае должна совместно использовать одну поверхность для окна). Это работает проще, чем вы можете ожидать - все, что делает SurfaceView, - это просит диспетчер окон создать новое окно, сообщая ему Z-порядок, что окно сразу за или перед окном SurfaceView, и позиционирует его для соответствия где SurfaceView отображается в содержащем окне. Если поверхность размещается за главным окном (в Z-порядке), SurfaceView также заполняет свою часть главного окна прозрачностью, чтобы поверхность была видна.

  • Растровое изображение - это просто интерфейс для некоторых данных пикселей. Пиксели могут быть выделены самим растровым изображением, когда вы его напрямую создаете, или он может указывать на пиксели, которыми он не владеет, например, что внутри происходит при подключении холста к поверхности для рисования. (Растровое изображение создается и указывает на текущий буфер рисования поверхности.)

Также имейте в виду, что из этого следует, что SurfaceView - довольно тяжелый объект. Если у вас есть несколько SurfaceView в конкретном пользовательском интерфейсе, остановитесь и подумайте, действительно ли это необходимо. Если у вас их больше двух, у вас почти наверняка их слишком много.

hackbod
источник
Большое спасибо! Ответ прояснил ситуацию. Однако часть о подключении Canvas к Surface остается неясной. Не представляю, где нужна такая операция. Следующим может быть пример этой операции: рисование Bitmap на Canvas, полученное из SurfaceHolder с помощью метода lockCanvas ()?
федорананиев 02
1
Вот как происходит рисование. Canvas - это API 2-го рисования. Если вы собираетесь рисовать на поверхности, вам нужно создать Canvas, указывающий на его буфер, чтобы использовать API рисования Canvas 2d для рисования на нем.
hackbod
6
В дополнение к #hackbod'sответу, он SurfaceViewтакже может быть отрисован из вторичного потока, что невозможно для Viewобъектов
Моханрадж Баласубраманиам
47

Концептуальный обзор Window, Surface, Canvas и Bitmap

Вот очень простой и простой концептуальный обзор того, как происходит взаимодействие между Window, Surface, Canvas и Bitmap.
Иногда визуальное представление очень помогает в понимании искаженных концепций.
Надеюсь, этот рисунок может кому-то помочь.

САБИХ
источник
4
Визуально Изображения лучше, чем текст: D
Maveň ツ
18

Bitmap - это просто оболочка для набора пикселей. Думайте об этом как о массиве пикселей с некоторыми другими удобными функциями.

Canvas - это просто класс, содержащий все методы рисования. Он похож на класс Graphics в AWT / Swing, если вы с ним знакомы. Вся логика того, как рисовать круг, прямоугольник и т. Д., Содержится внутри Canvas. Холст отрисовывается на растровом изображении или открытом контейнере GL, но нет причин, по которым в будущем его можно было бы расширить для рисования на других типах растров.

SurfaceView - это представление, содержащее поверхность. Поверхность похожа на растровое изображение (в ней есть хранилище пикселей). Я не знаю, как это реализовано, но я бы предположил, что это своего рода оболочка Bitmap с дополнительными методами для вещей, которые напрямую связаны с отображением экрана (это причина поверхности, Bitmap слишком общий). Вы можете получить Canvas со своей поверхности, которая действительно связывает Canvas с нижележащим растровым изображением.

Ваши вопросы.

1. К холсту прикреплено собственное растровое изображение. К поверхности прикреплен собственный холст.

Да, холст работает с растровым изображением (или открытой панелью GL). Surface предоставляет вам холст, который работает на любой поверхности, которая используется для своего хранилища пикселей в стиле Bitmap.

2. Все виды окна имеют одну и ту же поверхность и, следовательно, используют один холст.

Нет. Вы можете иметь столько видов поверхностей, сколько захотите.

3.SurfaceView - это подкласс View, который, в отличие от других подклассов View и самого View, имеет собственную поверхность для рисования.

Да. Так же, как ListView является подклассом View, который имеет собственную структуру данных List. Каждый подкласс View делает что-то свое.

sksamuel
источник
1
Итак, Bitmapа Surfaceэто просто разные виды хранилища пикселей и Canvasможно ли обернуть любой из них?
fyodorananiev 02
2
В основном да. За исключением того, что Canvas не может писать на поверхность, он работает на любой поверхности, которую использует в качестве собственного хранилища пикселей (не глядя на исходный код Android, я не могу точно сказать, что это такое). Вероятно, это какое-то расширение Bitmap, поскольку Canvas предоставляет конструкторы только для Bitmap и GL.
sksamuel 02
Отличная помощь, спасибо! Об ответе 2. В своем вопросе я имел в виду стандартные представления, а не SurfaceView. Предположим, у меня есть RelativeLayout с множеством полей и кнопок. В этом случае, прикреплена ли поверхность ко всему окну и используется ли она всеми представлениями в иерархии представлений?
fyodorananiev 02
1
Помните, что Surface - это просто набор пикселей. Таким образом, каждый вид поверхности имеет свою собственную поверхность, и каждый из них может отображаться в разных частях экрана. Они не обязательно заполняют экран (хотя это обычное использование для визуализации графики в полноэкранной игре).
sksamuel 02
1
Я действительно не стал бы считать Bitmap и Surface эквивалентными. Поверхность - это объект, о котором знает Surface Flinger, оконный композитор. То есть это что-то непосредственно видимое на экране, имеет Z-порядок на экране и т. Д.
hackbod 02