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 за преглед на живо.

Методи на жизнения цикъл на 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 — атрибут за преглед на живо на Custom UIView в Interface Builder, улеснява визуалното разработване
  • За статична графика кеширайте резултата чрез UIGraphicsImageRenderer и рисувайте готовото изображение — намалява натоварването на CPU

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

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също