Canvas в Android: что это такое, класс Canvas и методы draw

Автор: IT Sectr Опубликовано: 2026-07-21 Время чтения: 7 мин

Canvas в Android — это класс из пакета android.graphics, предоставляющий API для 2D-отрисовки на View. Canvas работает как холст, на котором разработчик рисует геометрические фигуры, текст, изображения и пути с помощью различных методов draw*. По данным Android Developers Documentation (2025), Canvas является основным инструментом для кастомной отрисовки в Android и используется вместе с классом Paint для задания стилей и цветов. Каждый вызов onDraw() получает готовый экземпляр Canvas, связанный с bitmap-буфером вью.

Главное

  • Canvas — класс для 2D-отрисовки в Android, предоставляет методы drawRect, drawCircle, drawText, drawBitmap и другие
  • Paint — класс, определяющий стиль отрисовки: цвет, толщину, заливку, эффекты (тень, градиент)
  • onDraw(Canvas) — метод View, в котором происходит вся отрисовка через полученный Canvas
  • Canvas.save() и restore() — управление стеком трансформаций для вложенных преобразований системы координат
  • Path — класс для построения произвольных контуров и кривых, передаётся в drawPath(Path, Paint)

Что такое Canvas в Android

Canvas — это центральный класс 2D-графики в Android, который предоставляет методы для рисования на плоскости. Каждый Canvas привязан к Bitmap — области памяти, в которую записываются результаты операций рисования. Когда View перерисовывается, система передаёт в onDraw() Canvas, уже связанный с буфером этого View.

Canvas работает в системе координат, где (0,0) — верхний левый угол, ось X идёт вправо, ось Y — вниз. Все операции рисования используют текущее состояние Canvas, включая матрицу трансформации, область отсечения (clip) и стиль Paint. По данным Android Documentation (2025), Canvas API включает более 30 методов draw* для разных типов графических примитивов.

Canvas и Hardware Acceleration

С Android 3.0 (API 11) Canvas поддерживает аппаратное ускорение через DisplayList. В ускоренном режиме Canvas-операции записываются в DisplayList и затем исполняются на GPU. Это даёт значительный прирост производительности, но накладывает ограничения: некоторые Canvas-операции (clipPath с не-Path-клипом) не поддерживаются в ускоренном режиме.

Основные методы Canvas для отрисовки

Canvas предоставляет набор методов для рисования базовых примитивов. Каждый метод принимает геометрические параметры и объект Paint, определяющий визуальный стиль.

МетодНазначениеПример
drawRect()Рисование прямоугольникаcanvas.drawRect(10f, 10f, 100f, 100f, paint)
drawCircle()Рисование кругаcanvas.drawCircle(50f, 50f, 30f, paint)
drawLine()Рисование линииcanvas.drawLine(0f, 0f, 100f, 100f, paint)
drawText()Рисование текстаcanvas.drawText("Hello", 10f, 20f, paint)
drawBitmap()Рисование изображенияcanvas.drawBitmap(bitmap, 0f, 0f, paint)
drawPath()Рисование произвольного путиcanvas.drawPath(path, paint)
drawOval()Рисование овалаcanvas.drawOval(rectF, paint)
drawArc()Рисование дуги или сектораcanvas.drawArc(rectF, 0f, 90f, true, paint)

Каждый метод может быть вызван в любой последовательности — Canvas рисует в порядке вызовов, накладывая новые элементы поверх предыдущих. Для сложных композиций используется техника многослойной отрисовки с сохранением и восстановлением состояния Canvas.

Класс Paint: настройка стилей и эффектов

Paint — это класс, который определяет, как Canvas будет рисовать. Без Paint методы Canvas бесполезны — он задаёт цвет, толщину линии, стиль заливки, размер текста, эффекты (тень, градиент, размытие) и режим наложения.

Paint имеет ключевые свойства: color (цвет), style (FILL, STROKE или FILL_AND_STROKE), strokeWidth (толщина линии), textSize (размер текста), isAntiAlias (сглаживание), shader (градиент или изображение). Создание объекта Paint — дорогая операция, поэтому его следует создавать один раз и переиспользовать.

kotlin
private val fillPaint = Paint().apply {
    color = Color.parseColor("#FF6200EE")
    style = Paint.Style.FILL
    isAntiAlias = true
}

private val strokePaint = Paint().apply {
    color = Color.WHITE
    style = Paint.Style.STROKE
    strokeWidth = 4f
    isAntiAlias = true
}

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    canvas.drawCircle(100f, 100f, 80f, fillPaint)
    canvas.drawCircle(100f, 100f, 80f, strokePaint)
}

В этом примере используются два Paint: один для заливки круга фиолетовым цветом, второй — для белой обводки. Разделение на fill и stroke — стандартная практика, позволяющая гибко управлять внешним видом без пересоздания объектов.

Shader и градиенты

Для градиентных заливок Paint принимает Shader — подклассы LinearGradient, RadialGradient, SweepGradient. Shader привязывается к Paint через метод setShader() и определяет, как цвет меняется по области отрисовки.

Трансформации Canvas: translate, rotate, scale

Canvas поддерживает матричные трансформации системы координат: translate() (сдвиг), rotate() (поворот), scale() (масштабирование) и skew() (наклон). Трансформации накапливаются: каждый последующий вызов применяется поверх предыдущих.

Управление стеком трансформаций осуществляется через save() и restore(). save() сохраняет текущее состояние Canvas (матрицу, clip) в стеке, restore() восстанавливает последнее сохранённое состояние. Между save() и restore() могут быть вложенные трансформации.

kotlin
override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)

    canvas.save() // Save initial state
    canvas.translate(100f, 100f) // Translate origin

    // First square
    canvas.drawRect(0f, 0f, 50f, 50f, fillPaint)

    canvas.save() // Save after translate
    canvas.rotate(45f, 25f, 25f) // Rotate around square center

    // Rotated square
    canvas.drawRect(0f, 0f, 50f, 50f, strokePaint)
    canvas.restore() // Restore after rotate

    canvas.restore() // Restore initial state
}

Всегда используйте save() перед началом трансформаций и restore() после их завершения. Несбалансированные save/restore приводят к накоплению матрицы и некорректной отрисовке последующих элементов.

Canvas с Bitmap и Path для сложной графики

Для сложной графики Canvas комбинируется с Bitmap и Path. Bitmap используется для загрузки изображений и кэширования отрендеренных кадров. Path — для построения произвольных кривых Безье, многоугольников и сложных контуров.

Offscreen Bitmap буфер

Техника offscreen-рендеринга: создаётся Bitmap, на него рисуется сложная сцена через отдельный Canvas, и затем готовый Bitmap выводится в onDraw() через drawBitmap(). Это позволяет обновлять сложную графику без полной перерисовки на каждый кадр.

kotlin
private var offscreenBitmap: Bitmap? = null
private var offscreenCanvas: Canvas? = null

fun buildOffscreenScene(width: Int, height: Int) {
    offscreenBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
    offscreenCanvas = Canvas(offscreenBitmap)

    // Render scene once
    offscreenCanvas!!.drawColor(Color.WHITE)
    drawGrid(offscreenCanvas!!)
    drawComplexShape(offscreenCanvas!!)
}

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    offscreenBitmap?.let { canvas.drawBitmap(it, 0f, 0f, null) }
}

Path используется для построения сложных контуров: кривые Безье (quadTo, cubicTo), дуги (arcTo), линии (lineTo). Path может быть замкнутым (close()) для залитых фигур или открытым для линий. Основные методы drawPath() объединяют Path и Paint для конечной отрисовки.

Оптимизация отрисовки Canvas

Производительность Canvas-отрисовки напрямую влияет на FPS приложения. Основные проблемы: избыточные аллокации в onDraw(), частые invalidate() и неоптимальное использование Hardware Acceleration.

Создавайте объекты за пределами onDraw()

Paint, Path, Rect, RectF и другие объекты должны создаваться однократно в инициализаторе или методе setup(). Каждая аллокация в onDraw() создаёт нагрузку на сборщик мусора, что приводит к микро-лагам. Исключение — static или companion object для immutable-объектов.

Используйте clipRect() для ограничения области

Если большая часть View скрыта за пределами видимой области (например, в ScrollView), используйте canvas.clipRect() для ограничения отрисовки. Hardware Acceleration в этом случае дополнительно оптимизирует отсечение невидимых пикселей.

kotlin
override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)

    // Clip to visible area
    canvas.save()
    canvas.clipRect(scrollX, scrollY, scrollX + width, scrollY + height)

    // Render large scene
    renderScene(canvas)
    canvas.restore()
}

Используйте View.setLayerType() с LAYER_TYPE_HARDWARE для View со сложной Canvas-графикой, которая обновляется редко. Для часто обновляемой анимации, наоборот, используйте LAYER_TYPE_NONE, чтобы избежать дорогого обновления аппаратного слоя. Профилируйте через GPU Profile Rendering и Android Studio Profiler.

Часто задаваемые вопросы

Можно ли создать Canvas без View?

Да, можно создать Canvas(Bitmap) — конструктор, принимающий Bitmap. Это используется для offscreen-рендеринга: вы рисуете на Bitmap, а затем выводите его через drawBitmap(). Также Canvas может быть создан из Surface (для SurfaceView) или через Picture.

Чем отличается Canvas от SurfaceView?

Canvas — это API для рисования на View в UI-потоке. SurfaceView — это отдельный Surface, который может обновляться из фонового потока через собственный Canvas (lockCanvas() / unlockCanvasAndPost()). SurfaceView предпочтителен для игр и видео.

Почему Canvas не рисует после трансформации?

Самая частая причина — несбалансированные save() и restore(). Если после трансформации (translate, rotate) не вызвать restore(), Canvas остаётся в изменённой системе координат, и последующие элементы рисуются со смещением. Проверьте пары save()/restore().

Как нарисовать текст по центру Canvas?

Используйте Paint.setTextAlign(Paint.Align.CENTER) для горизонтального центрирования и Paint.getTextBounds() или Paint.descent() / ascent() для вертикального. Центрирование: canvas.drawText(text, centerX, centerY - (ascent + descent) / 2, paint).

Поддерживает ли Canvas анимацию?

Canvas сам по себе не анимирует — он только рисует текущее состояние. Анимация достигается через последовательные вызовы invalidate() (или postInvalidateOnAnimation()), каждый раз рисуя новый кадр в onDraw(). Для плавных анимаций используйте ValueAnimator или Choreographer для синхронизации с Vsync.

Итоги

  • Canvas — центральный класс 2D-отрисовки в Android, предоставляет методы draw* для рисования примитивов, текста и изображений
  • Paint — определяет визуальный стиль (цвет, толщину, заливку, шейдеры); создаётся один раз и переиспользуется
  • save() / restore() — управление стеком трансформаций; каждая трансформация должна быть в паре save/restore
  • Path — построение произвольных контуров и кривых Безье для сложной векторной графики
  • Offscreen Bitmap — техника кэширования сложных сцен через Canvas(Bitmap) для уменьшения нагрузки на onDraw()
  • Hardware Acceleration — GPU-ускорение Canvas с Android 3.0, накладывает ограничения на некоторые операции (clipPath)
  • Профилирование — GPU Profile Rendering и Android Studio Profiler обязательны для поиска узких мест в onDraw()

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также