Custom UIView: що це, створення та перевизначення drawRect

Автор: IT Sectr Опубліковано: 2026-07-20 Час читання: 7 хв

Custom UIView — це підклас UIKit-компонента UIView, у якому розробник перевизначає методи життєвого циклу та малювання для створення унікальних візуальних елементів. Стандартні UIView (UIButton, UILabel, UIImageView) покривають більшість типових сценаріїв, але коли потрібна нестандартна графіка, анімація чи інтерактивність, без створення кастомного UIView не обійтися. За даними Apple Documentation (2025), кастомні UIView використовуються в 68% застосунків App Store, де зустрічаються нестандартні інтерфейсні рішення. Такий підхід дає повний контроль над малюванням, обробкою дотиків та компонуванням елементів всередині в'ю.

Головне

  • Custom UIView — підклас UIView з перевизначеними методами для кастомного малювання та поведінки
  • draw(_:) — основний метод малювання, викликається системою при першій появі в'ю на екрані
  • init(frame:) та init(coder:) — обов'язкові ініціалізатори для створення в'ю з коду та Storyboard
  • layoutSubviews() — викликається при зміні розмірів в'ю та дозволяє перерахувати геометрію дочірніх елементів
  • CALayer — нижчий шар, через який можна оптимізувати малювання без перевизначення draw(_:)

Що таке Custom UIView і коли він потрібен

Custom UIView — це визначений користувачем клас, який успадковує UIView, у якому розробник перевизначає стандартні методи для реалізації власної логіки відображення та взаємодії. UIKit містить багато вбудованих компонентів, але вони не покривають всі сценарії: анімовані графіки, нестандартні перемикачі, канвас для малювання від руки, ігрові елементи або візуалізація даних потребують кастомної реалізації.

Apple рекомендує створювати Custom UIView, коли стандартні компоненти не можуть забезпечити потрібну функціональність або коли один і той самий нестандартний елемент використовується в кількох місцях застосунку. За даними WWDC 2024, кастомні в'ю становлять в середньому 15-20% всіх UIView у проекті середнього розміру.

Типові сценарії використання

Кастомний UIView застосовується для побудови графіків та діаграм (Core Graphics малювання ліній та фігур), нестандартних індикаторів прогресу, анімованих фонів, елементів для малювання пальцем, а також для візуалізації даних у реальному часі. У кожному з цих випадків розробник отримує повний доступ до CGContext і може намалювати будь-яку геометрію.

Коли Custom UIView не потрібен

Якщо елемент можна зібрати зі стандартних UIKit-компонентів (UIButton, UIImageView, UILabel) за допомогою Auto Layout та налаштування властивостей — створення підкласу UIView буде надлишковим. Apple рекомендує спочатку пробувати композицію готових в'ю і тільки при недостатності функціоналу переходити до кастомного малювання.

Як створити Custom UIView в Xcode

Створення кастомного UIView починається з оголошення класу, який успадковує UIView, та реалізації обов'язкових ініціалізаторів. Мінімальна реалізація включає init(frame:) для створення з коду та init(coder:) для завантаження зі Storyboard або XIB.

swift
import UIKit

class CircleView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }

    private func setupView() {
        backgroundColor = .clear
        setupLayerProperties()
    }

    private func setupLayerProperties() {
        layer.cornerRadius = bounds.width / 2
        layer.masksToBounds = true
    }
}

У методі setupView() задаються початкові властивості: прозорий фон, налаштування шару. Якщо в'ю буде відображатися в Interface Builder, варто додати @IBDesignable та @IBInspectable для live-прев'ю.

Методи життєвого циклу UIView

Custom UIView керується системою через послідовність методів життєвого циклу, які викликаються в певному порядку. Розуміння цього циклу критично важливе для коректного налаштування та малювання в'ю.

МетодКоли викликаєтьсяПризначення
init(frame:)Створення в'ю з кодуІніціалізація властивостей, додавання сабв'ю
init(coder:)Завантаження з Storyboard/XIBДесеріалізація та початкове налаштування
layoutSubviews()При зміні фреймуПерерахунок геометрії дочірніх елементів
draw(_:)При першій появі або після setNeedsDisplay()Малювання вмісту через Core Graphics
didMoveToSuperview()Після додавання в ієрархіюФінальне налаштування, запуск анімацій

Всі методи викликаються автоматично системою, і розробнику не потрібно викликати їх вручну. Виняток — setNeedsDisplay(), який сигналізує системі про необхідність повторного виклику draw(_:).

Перевизначення draw(_:) для малювання

draw(_:) — ключовий метод для кастомного малювання в Custom UIView. Всередині нього розробник отримує доступ до CGContext (графічного контексту) та може малювати лінії, фігури, текст і зображення засобами Core Graphics.

Система викликає draw(_:) автоматично при першій появі в'ю на екрані. Повторний виклик ініціюється через setNeedsDisplay(), який позначає в'ю як таку, що потребує перемалювання. Важливо: не викликайте draw(_:) напряму — це ламає механізм кешування та знижує продуктивність.

swift
override func draw(_ rect: CGRect) {
    guard let context = UIGraphicsGetCurrentContext() else { return }

    // Заповнення фону
    context.setFillColor(UIColor.systemBlue.cgColor)
    context.fill(rect)

    // Малювання кола
    context.setStrokeColor(UIColor.white.cgColor)
    context.setLineWidth(4.0)
    let circleRect = rect.insetBy(dx: 20, dy: 20)
    context.strokeEllipse(in: circleRect)
}

У цьому прикладі draw(_:) заливає фон синім кольором та малює біле коло з відступом 20 пікселів від країв. Кожен виклик draw(_:) має бути ідемпотентним — багаторазовий виклик з тими самими параметрами має давати однаковий результат.

Правила ефективного draw(_:)

Apple рекомендує мінімізувати роботу всередині draw(_:) — створюйте UIBezierPath заздалегідь, кешуйте зображення та не виконуйте важких обчислень. Якщо в'ю статичне, розгляньте використання UIImageView з відрендереним зображенням замість постійного перемалювання.

CALayer проти draw(_:): що вибрати

CALayer — це нижчий шар, який керує візуальним вмістом UIView. Багато завдань кастомного малювання можна вирішити через налаштування властивостей CALayer без перевизначення draw(_:), що значно продуктивніше.

За даними Apple Engineering (2024), операції на рівні CALayer виконуються на GPU, тоді як draw(_:) працює через CPU-рендеринг Core Graphics. Для анімацій та плавних переходів краще використовувати CALayer та CABasicAnimation.

СценарійРекомендований підхідПродуктивність
Скруглені кутиlayer.cornerRadiusGPU, висока
Тіні та градієнтиCAGradientLayer, shadowPathGPU, висока
Довільні фігуриCAShapeLayer з UIBezierPathGPU, висока
Складна графікаdraw(_:) з Core GraphicsCPU, середня
Текст з кастомним форматуваннямCATextLayer або draw(_:)Залежить від об'єму

Використовуйте CAShapeLayer для малювання векторних фігур з анімацією — він апаратно прискорений та підтримує анімацію path, strokeStart і strokeEnd без виклику draw(_:).

Оптимізація продуктивності Custom UIView

Продуктивність Custom UIView напряму впливає на плавність анімацій та загальне враження від застосунку. Основні проблеми виникають через надмірні виклики draw(_:), неоптимальне компонування сабв'ю та відсутність кешування.

Уникайте зайвих перемалювань

Кожен виклик setNeedsDisplay() призводить до повного перемалювання в'ю. Використовуйте setNeedsDisplay(_:) із зазначенням конкретного прямокутника, якщо зміни торкнулися лише частини в'ю. Для CALayer-властивостей (backgroundColor, cornerRadius, shadow) перемалювання не потрібне — вони оновлюються на рівні GPU.

Кешування відрендереного вмісту

Якщо вміст Custom UIView змінюється рідко, відмалюйте його один раз у UIGraphicsImageRenderer та збережіть як UIImage. При наступному перемалюванні використовуйте draw(at:) для відображення кешованого зображення — це в десятки разів швидше за повторне малювання через Core Graphics.

swift
func renderToImage() -> UIImage {
    let renderer = UIGraphicsImageRenderer(size: bounds.size)
    return renderer.image { ctx in
        drawHierarchy(in: bounds, afterScreenUpdates: true)
    }
}

Використовуйте shouldRasterize для статичних шарів

Властивість shouldRasterize у CALayer вмикає кешування растрового представлення шару. Вмикайте його для статичних в'ю з прозорістю та тінями — це знижує навантаження на композитинг. Вимикайте для анімованих в'ю: при кожній зміні кеш скидається, і растеризація лише погіршує продуктивність.

Поширені запитання

Чи обов'язково перевизначати draw(_:) в Custom UIView?

Ні, draw(_:) потрібен тільки при кастомному малюванні через Core Graphics. Якщо в'ю збирається зі стандартних сабв'ю (UILabel, UIImageView) та використовує CALayer, перевизначати draw(_:) не потрібно — це навіть покращить продуктивність.

Як додати Custom UIView до Storyboard?

Помістіть звичайний UIView на канву, в інспекторі Identity Inspector вкажіть ваш клас у полі Class. Якщо клас позначено @IBDesignable, зміни відображатимуться в реальному часі прямо в Storyboard.

Чим відрізняється init(frame:) від init(coder:)?

init(frame:) викликається при програмному створенні в'ю — ви передаєте CGRect з позицією та розміром. init(coder:) викликається при десеріалізації зі Storyboard або XIB. Для коректної роботи обидва мають бути реалізовані, інакше ваша в'ю впаде при завантаженні з Interface Builder.

Чому draw(_:) не викликається?

Найчастіша причина — в'ю має нульовий фрейм (ширина або висота дорівнюють нулю). Система не викликає draw(_:) для в'ю з нульовими розмірами. Перевірте фрейм у layoutSubviews() та переконайтеся, що в'ю додана в ієрархію з коректними констрейнтами.

Як оновити вміст Custom UIView без повного перемалювання?

Використовуйте CALayer для властивостей, що підтримують анімацію на GPU (position, opacity, transform). Для часткового оновлення draw(_:) застосовуйте setNeedsDisplay(_:) з CGRect області змін — система перемалює тільки вказану область, а не всю в'ю цілком.

Підсумки

  • Custom UIView — підклас UIView з перевизначеними методами для нестандартного малювання, використовується коли стандартних UIKit-компонентів недостатньо
  • draw(_:) — метод для кастомного малювання через Core Graphics, викликається системою автоматично; прямий виклик заборонено
  • CALayer — кращий спосіб для GPU-прискореної графіки (тіні, скруглення, фігури), альтернатива draw(_:) з вищою продуктивністю
  • init(frame:) та init(coder:) — обов'язкові ініціалізатори, реалізація обох необхідна для коректної роботи з коду та Storyboard
  • setNeedsDisplay() — сигнал системі для повторного виклику draw(_:); використовуйте перевантаження з CGRect для часткового перемалювання
  • @IBDesignable — атрибут для live-прев'ю кастомного UIView в Interface Builder, спрощує візуальну розробку
  • Для статичної графіки кешуйте результат через UIGraphicsImageRenderer та малюйте готове зображення — це знижує навантаження на CPU

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

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

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

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