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-буфером вьe.

Головне

  • 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 та апаратне прискорення

З 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() та неоптимальне використання апаратного прискорення.

Створюйте об—єкти за межами onDraw()

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

Використовуйте clipRect() для обмеження області

Якщо велика частина View прихована за межами видимоє області (наприклад, у ScrollView), використовуйте canvas.clipRect() для обмеження рендерингу. Апаратне прискорення в цьому випадку додатково оптимізує відсікання невидимих пікселів.

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()
  • Апаратне прискорення — GPU-прискорення Canvas з Android 3.0, накладає обмеження на деякі операції (clipPath)
  • Профілювання — GPU Profile Rendering та Android Studio Profiler обов—єязкові для пошуку вузьких місць в onDraw()

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

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