Где реализуется кастомная логика отрисовки UIView в UIKit?

Ответ

Кастомная отрисовка в UIView выполняется путем переопределения метода draw(_ rect: CGRect). Этот метод предоставляет графический контекст (CGContext) для рисования с помощью Core Graphics.

Базовый пример:

class CustomView: UIView {
    override func draw(_ rect: CGRect) {
        // 1. Получаем текущий графический контекст
        guard let context = UIGraphicsGetCurrentContext() else { return }

        // 2. Настраиваем параметры рисования
        context.setFillColor(UIColor.systemBlue.cgColor)
        context.setStrokeColor(UIColor.black.cgColor)
        context.setLineWidth(2.0)

        // 3. Определяем прямоугольник для рисования
        let drawingRect = CGRect(x: 20, y: 20, width: 100, height: 100)

        // 4. Рисуем и заливаем прямоугольник
        context.addRect(drawingRect)
        context.drawPath(using: .fillStroke)
    }
}

Ключевые принципы:

  • Не вызывайте draw(_:) напрямую. Чтобы система вызвала этот метод, необходимо пометить view как требующее перерисовки:
    myCustomView.setNeedsDisplay() // Перерисовать всю view
    myCustomView.setNeedsDisplay(rect) // Перерисовать только указанную область
  • Графический контекст доступен только внутри draw(_:). Не пытайтесь сохранить UIGraphicsGetCurrentContext() для использования позже.
  • Для производительности: Ограничивайте область перерисовки (rect), используйте setNeedsDisplay(in:). Для сложной векторной графики рассмотрите использование CAShapeLayer.
  • Альтернатива для анимаций: Для анимированных или часто меняющихся элементов более эффективно использовать CALayer и его подклассы (например, CAShapeLayer), так как они оптимизированы аппаратным ускорением.

Ответ 18+ 🔞

Смотри, ну вот объясняю, как нарисовать свою хрень в UIView. Это ж не просто так, блядь, взять и намалевать. Тут целая система, ёпта!

Если хочешь свою кастомную хуйню нарисовать, тебе нужно переопределить метод draw(_ rect: CGRect). Внутри него тебе дадут волшебную кисть — графический контекст (CGContext), и ты уже можешь хуячить туда всё, что душе угодно, через Core Graphics.

Вот, смотри, элементарный пример, чтоб понятно было:

class CustomView: UIView {
    override func draw(_ rect: CGRect) {
        // 1. Достаём эту самую волшебную кисть — контекст
        guard let context = UIGraphicsGetCurrentContext() else { return }

        // 2. Готовим краски, сука
        context.setFillColor(UIColor.systemBlue.cgColor) // Цвет заливки
        context.setStrokeColor(UIColor.black.cgColor)    // Цвет обводки
        context.setLineWidth(2.0)                        // Толщина линии

        // 3. Решаем, где будем рисовать наш шедевр
        let drawingRect = CGRect(x: 20, y: 20, width: 100, height: 100)

        // 4. Ну и хуярим прямоугольник, заливаем и обводим
        context.addRect(drawingRect)
        context.drawPath(using: .fillStroke)
    }
}

А теперь, блядь, главные правила, которые в голове держать надо:

  • Не вздумай вызывать draw(_:) руками, как дурак! Система сама его вызовет, когда надо. А чтобы ей намекнуть, что пора, используй:
    myCustomView.setNeedsDisplay() // Эй, система, перерисуй всю вьюху, нахуй!
    myCustomView.setNeedsDisplay(rect) // Перерисуй только вот этот кусок, оптимизация же!
  • Графический контекст — он как одноразовый шприц. Только внутри draw(_:) он живёт. Не пытайся его вытащить и сохранить в свойство, чтобы потом дорисовать — нихуя не выйдет, получишь nil и депрессию.
  • Про производительность: Не перерисовывай всё подряд, если можно только кусочек (rect). Если рисуешь какую-то ебанутую сложную векторную графику, которая не меняется каждую секунду, может, лучше на CAShapeLayer посмотреть? Оно железом ускоряется.
  • Для всего, что дрыгается и мигает: Забей на draw(_:) в лоб. Для анимаций и динамики CALayer (и его дети вроде CAShapeLayer) — это твои лучшие друзья. Они через GPU работают, а не через CPU, поэтому всё будет гладко, как жопа младенца.