Кастомные View и рисование в мобильной разработке: суть, какие API и как работает

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

Кастомные View — основа уникального интерфейса любого мобильного приложения. Кастомные View в мобильных приложениях позволяют создавать собственную графику, анимации и элементы, недоступные в стандартных компонентах. По данным Apple Developer, 2025, drawRect остаётся основным методом кастомного рисования в мобильной разработке на iOS. На Android ту же роль выполняет onDraw с Canvas, а во Flutter — CustomPainter.

Главное

  • Кастомные View — пользовательские компоненты с собственной логикой отрисовки, размера и поведения в мобильных приложениях.
  • drawRect — метод UIView на iOS для кастомного рисования через Core Graphics и CGContext.
  • onDraw — метод View на Android для рисования через Canvas и Paint с системой измерения onMeasure.
  • CustomPainter — класс Flutter для рисования на Canvas с методами paint и shouldRepaint.
  • Измерение — процесс определения размеров View через sizeThatFits на iOS, onMeasure на Android и computeDryLayout во Flutter.

Что такое кастомные View и зачем они нужны в мобильных приложениях

Кастомные View — это пользовательские компоненты интерфейса, которые переопределяют стандартные методы отрисовки и измерения для создания уникальной графики. Графики, анимации, диаграммы, кастомные элементы чата и AR-маски — типичные сценарии применения кастомных View в мобильных приложениях. Стандартные UI-компоненты (Button, TextView, Label) покрывают 80% задач, но оставшиеся 20% требуют полного контроля над рисованием в мобильной разработке. Рисование в мобильной разработке — навык, который отличает junior-разработчика от senior.

Когда кастомные View оправданы

Кастомные View в мобильных приложениях нужны для уникальной 2D-графики, сложных анимаций, графиков и визуализации данных. Если стандартный UIKit не предоставляет нужного элемента — создаётся кастомный View. В мобильных приложениях кастомные View используются для прогресс-баров, кастомных кнопок, градиентных заливок, анимированных иконок и канвасов для рисования пальцем. Важно не злоупотреблять — для простых стилей достаточно настроить стандартные компоненты через Appearance API.

Кастомные View на iOS: drawRect и Core Graphics

На iOS кастомные View создаются через наследование от UIView и переопределение метода drawRect. drawRect вызывается при первой отрисовке и после каждого вызова setNeedsDisplay(). Внутри drawRect разработчик получает CGContext через UIGraphicsGetCurrentContext() — холст для линий, фигур, градиентов и текста. Core Graphics (Quartz 2D) — низкоуровневый движок рендеринга на CPU, который даёт полный контроль над каждым пикселем. UIBezierPath — удобная обёртка для создания путей с лаконичным синтаксисом.

swift
class CircleView: UIView {
    private var fillColor: UIColor = .systemBlue

    override func drawRect(_ rect: CGRect) {
        guard let ctx = UIGraphicsGetCurrentContext() else { return }
        ctx.setFillColor(fillColor.cgColor)
        ctx.addEllipse(in: bounds.insetBy(dx: 4, dy: 4))
        ctx.drawPath(using: .fill)
    }

    func updateColor(_ newColor: UIColor) {
        fillColor = newColor
        setNeedsDisplay()
    }
}

Core Graphics: CGContext, CGGradient и трансформации

Core Graphics предоставляет CGContext — холст для всех операций рисования. CGGradient создаёт линейные и радиальные градиенты с поддержкой CGColorSpace (sRGB, Display P3). Трансформации выполняются через CGAffineTransform — матрица 3x3 для поворота, масштабирования и смещения. CGContextTranslateCTM, CGContextRotateCTM и CGContextScaleCTM изменяют систему координат. Core Graphics работает на CPU, поэтому сложная графика может нагружать процессор — для GPU-ускорения используйте Metal.

UIBezierPath для создания фигур

UIBezierPath — объектно-ориентированная обёртка над CGPath. Метод addArc(withCenter:radius:startAngle:endAngle:clockwise:) создаёт дуги и окружности, addCurve — кривые Безье. Пути поддерживают операции union, intersection и subtraction через addClip. UIBezierPath удобен для кастомных масок (maskView), обтравочных контуров и сложных фигур — звезды, сердечки, кастомные иконки.

Кастомные View на Android: onDraw и Canvas

На Android кастомный View наследуется от View с переопределением onDraw(Canvas). Canvas содержит все методы рисования в мобильной разработке: drawCircle, drawRect, drawLine, drawText, drawBitmap, drawPath и drawRoundRect. Paint настраивает параметры — цвет, толщину линии, стиль (FILL, STROKE, FILL_AND_STROKE), сглаживание (isAntiAlias) и размер текста. onDraw вызывается каждый раз при invalidate() и не должен содержать тяжёлых операций — все вычисления кэшируются.

kotlin
class CustomCircleView(context: Context, attrs: AttributeSet?)
    : View(context, attrs) {

    private val paint = Paint().apply {
        style = Paint.Style.FILL
        color = Color.BLUE
        isAntiAlias = true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val cx = width / 2f
        val cy = height / 2f
        val radius = minOf(cx, cy) - 4f
        canvas.drawCircle(cx, cy, radius, paint)
    }
}

Path и анимации на Android

Path на Android — аналог UIBezierPath: addCircle, addRect, addOval, lineTo, cubicTo и quadTo. PathMeasure вычисляет длину пути и координаты в произвольной точке — полезно для анимации движения объекта вдоль пути. Для анимаций используется ValueAnimator с invalidate() в колбэке. Animator может менять цвет, радиус, положение — любое свойство, влияющее на рисование. Кастомные View на Android также поддерживают StateListDrawable и animated-vector для анимации через XML.

Shader и градиенты в Canvas

Градиенты на Android задаются через Shader — LinearGradient, RadialGradient и SweepGradient. Shader присваивается Paint через paint.setShader(shader). LinearGradient генерирует линейный градиент между двумя точками с опциональными позициями цветов. RadialGradient — радиальный от центра к краям. SweepGradient — конический вокруг центральной точки. Shader.TileMode (CLAMP, REPEAT, MIRROR) определяет поведение за пределами области.

CustomPainter во Flutter: рисование на Canvas

Flutter использует CustomPainter — класс с методами paint(Canvas canvas, Size size) и shouldRepaint. Canvas во Flutter предоставляет такие же методы, как в Android: drawCircle, drawRect, drawLine, drawPath, drawParagraph и drawImage. Paint в Flutter настраивает цвет, толщину, стиль и сглаживание. Flutter не использует drawRect или onDraw — всё рисование идёт через CustomPainter, встроенный в CustomPaint виджет.

dart
class CirclePainter extends CustomPainter {
  final Color color;

  CirclePainter({required this.color});

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = color
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    final radius = size.shortestSide / 2 - 4;
    canvas.drawCircle(size.center(Offset.zero), radius, paint);
  }

  @override
  bool shouldRepaint(CirclePainter oldDelegate) =>
    oldDelegate.color != color;
}

shouldRepaint и RepaintBoundary

shouldRepaint определяет, нужно ли перерисовывать CustomPainter. Возвращайте true только при изменении данных, влияющих на отрисовку — цвет, размер, данные графика. RepaintBoundary изолирует перерисовку в отдельный слой — используйте для виджетов, которые редко меняются. Во Flutter нет setNeedsDisplay или invalidate — перерисовка запускается через setState или ValueNotifier с прослушиванием изменений.

Gradient и трансформации во Flutter

Flutter поддерживает LinearGradient, RadialGradient и SweepGradient — те же типы, что в Android. Gradient создаёт Shader для Paint через createShader(Rect bounds). Трансформации выполняются через canvas.rotate, canvas.scale, canvas.translate и canvas.skew. Flutter использует матрицу преобразований 4x4 (Matrix4) для Transform виджета. Анимации рисования во Flutter делаются через AnimationController в связке с setState для перерисовки CustomPainter.

Измерение кастомных View: методы sizeThatFits, onMeasure и computeDryLayout

Корректное измерение кастомных View — основа предсказуемого поведения интерфейса. На iOS размер View определяется через sizeThatFits и intrinsicContentSize. sizeThatFits возвращает оптимальный размер для заданных ограничений. intrinsicContentSize — естественный размер контента без внешних ограничений. На Android измерение реализуется в onMeasure с параметрами MeasureSpec (UNSPECIFIED, EXACTLY, AT_MOST). Во Flutter размер передаётся в paint(Canvas, Size) и может быть вычислен через computeDryLayout или LayoutBuilder.

sizeThatFits и intrinsicContentSize на iOS

intrinsicContentSize возвращает CGSize — ествественный размер View на основе его контента. setContentHuggingPriority и setContentCompressionResistancePriority управляют поведением при растяжении и сжатии. sizeThatFits вызывается системой для вычисления размера в Auto Layout. Для кастомных View переопределите intrinsicContentSize, если ваш компонент имеет естественный размер — например, круг всегда должен быть 100x100.

onMeasure и MeasureSpec на Android

onMeasure принимает widthMeasureSpec и heightMeasureSpec. MeasureSpec содержит режим и размер: UNSPECIFIED (без ограничений, View сам выбирает размер), EXACTLY (точный размер от родителя), AT_MOST (максимальный размер). setMeasuredDimension(width, height) сохраняет результат измерения. При изменении данных вызывайте requestLayout() для повторного измерения. Вложенные ViewGroup требуют переопределения onLayout для расстановки дочерних элементов.

ПлатформаМетод измеренияВызов при измененииВозврат
iOSsizeThatFits / intrinsicContentSizesetNeedsLayout / invalidateIntrinsicContentSizeCGSize
AndroidonMeasure / setMeasuredDimensionrequestLayout / invalidatevoid (сохраняет размер)
FluttercomputeDryLayoutsetState / LayoutBuilderSize

computeDryLayout во Flutter

computeDryLayout — метод RenderObject для вычисления размера без полного цикла компоновки. LayoutBuilder.getSize — альтернатива для получения доступного пространства в build-методе. Во Flutter размер холста передаётся в paint как Size и не требует отдельного измерения — CustomPainter рисует внутри переданных границ. Однако для кастомных RenderObject надо переопределять performLayout и computeDryLayout.

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

Что такое drawRect на iOS и когда он вызывается?

drawRect — метод UIView для кастомного рисования через Core Graphics. Вызывается при первой отрисовке View и после каждого вызова setNeedsDisplay(). Используйте CGContext внутри drawRect для линий, фигур и текста.

Как рисовать на Android с помощью Canvas?

Создайте класс, наследующий View, переопределите onDraw(Canvas canvas) и используйте Canvas API: drawCircle, drawRect, drawPath. Paint настраивает цвет, толщину и стиль. Для обновления вызывайте invalidate().

Что такое CustomPainter во Flutter?

CustomPainter — класс Flutter для кастомного рисования на Canvas. Реализуйте методы paint(Canvas, Size) и shouldRepaint. Размещается через виджет CustomPaint. Во Flutter нет drawRect — всё рисование идёт через CustomPainter.

Как измерить размер кастомного View?

На iOS используйте sizeThatFits и intrinsicContentSize. На Android — onMeasure с MeasureSpec. Во Flutter размер передаётся в paint(Canvas, Size) или вычисляется через computeDryLayout. Каждая платформа использует свой метод измерения.

Когда нужно использовать кастомные View вместо стандартных компонентов?

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

Итоги

  • Кастомные View — основа уникального интерфейса для графиков, анимаций и нестандартных элементов в мобильных приложениях.
  • drawRect — метод iOS для рисования через Core Graphics с CGContext и UIBezierPath.
  • onDraw — метод Android для рисования через Canvas и Paint с поддержкой Path и Shader.
  • CustomPainter — класс Flutter для рисования на Canvas с shouldRepaint и RepaintBoundary.
  • Измерение — валидация размеров через sizeThatFits (iOS), onMeasure (Android) и computeDryLayout (Flutter).
  • Рисование в мобильной разработке на всех платформах следует единому паттерну: получить контекст, настроить стили и нарисовать примитивы.
  • Кэшируйте объекты рисования (Paint, Path) — не создавайте их внутри drawRect, onDraw или paint для стабильной производительности.

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

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

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