Мы не раз видели, как заказчик приносит макет с диаграммой, где столбцы взлетают один за другим, а линия вырисовывается словно рукой художника. На первый взгляд — простая анимация. Но когда доходит до кода, выясняется, что готовая библиотека не умеет такой stagger-эффект, а кастомная реализация на Canvas требует глубокого понимания Core Animation или Android Canvas API. Мы берёмся за такие задачи и за 1-3 дня внедряем анимацию любого уровня сложности, будь то bar chart, line chart или круговая диаграмма. В этой статье разберём типовые проблемы и способы их решения.
Перед тем как выбрать библиотеку или писать с нуля, важно понимать, какие анимации нужны: простое появление или последовательный stagger, поддержка touch-событий и tooltip, работа с большими данными (500+ точек) без просадки FPS. Мы используем профилирование (Instruments, Android Profiler) на каждом этапе, чтобы гарантировать 60fps.
Как выбрать между библиотекой и кастомным Canvas?
Выбор между готовой библиотекой и кастомной реализацией — ключевое решение. Библиотеки вроде MPAndroidChart или Swift Charts дают 80% нужного за 20% времени, но кастомизация анимации в них ограничена. Например, MPAndroidChart поддерживает animateX() и animateY(), но настроить easing per-bar или сделать stagger-анимацию (столбцы появляются поочерёдно) — нельзя без кастомного Renderer. Кастомный Canvas оправдан, когда нужен нестандартный тип чарта, stagger-эффект, анимация отдельных точек или интерактивный tooltip.
| Критерий | Библиотека (MPAndroidChart, Swift Charts) | Кастомный Canvas |
|---|---|---|
| Время реализации | Часы | 1-3 дня |
| Кастомизация анимации | Ограничена (easing, stagger) | Полная (любая кривая, задержки) |
| Производительность 500+ точек | Средняя (возможны лаги) | Высокая (downsampling + LOD) |
| Поддержка жестов | Встроенная (неглубокая) | Настраиваемая (любая логика) |
Почему stagger-анимация важна для восприятия данных?
Stagger-анимация (поочерёдное появление элементов) привлекает внимание к каждому столбцу или точке, делая данные более читаемыми. Кастомная реализация на Canvas даёт в 3 раза больше контроля над анимацией по сравнению с готовыми библиотеками, что критично для сложных дашбордов. Мы реализовали её на Flutter через AnimationController + Interval:
// Каждый столбец анимируется с задержкой 80мс
for (int i = 0; i < bars.length; i++) {
final start = (i * 0.08).clamp(0.0, 1.0);
final end = (start + 0.4).clamp(0.0, 1.0);
animations[i] = Tween(begin: 0.0, end: bars[i].value).animate(
CurvedAnimation(
parent: controller,
curve: Interval(start, end, curve: Curves.easeOutCubic),
),
);
}
На iOS аналогичный эффект достигается через CAKeyframeAnimation с keyTimes — каждый CAShapeLayer (один столбец) получает смещённый beginTime:
bars.enumerated().forEach { index, layer in
let anim = CABasicAnimation(keyPath: "bounds.size.height")
anim.beginTime = CACurrentMediaTime() + Double(index) * 0.08
anim.duration = 0.4
anim.timingFunction = CAMediaTimingFunction(name: .easeOut)
layer.add(anim, forKey: nil)
}
Line chart анимируется через CAShapeLayer с strokeEnd: 0 → 1. Для добавления точек-маркеров, которые появляются в момент прохождения «кисти», нужно синхронизировать появление CALayer с прогрессом strokeEnd. Реализуем через CAAnimationDelegate.animationDidStop для каждого сегмента или через displayLink с отслеживанием presentation().strokeEnd.
Интерактивный tooltip: как не потерять FPS
Tooltip, следующий за пальцем по графику — отдельная задача. На iOS: UIGestureRecognizer → пересчёт координаты в значение данных → UIView.animate для tooltip. Важно использовать setNeedsDisplay() только для той части CALayer, где рисуется highlight-линия — перерисовка всего canvas убивает FPS при быстром движении пальца. Мы гарантируем 60fps даже при интенсивном взаимодействии благодаря инкрементальному рендерингу.
Что входит в работу
- Исходный код анимированного компонента на Swift/Kotlin/Dart/TypeScript
- Документация по кастомизации (цвета, шрифты, параметры анимации)
- Интеграция в существующий проект и настройка тестового окружения
- Оптимизация производительности (downsampling для наборов >500 точек, LOD)
- Гарантия 60fps на устройствах среднего сегмента
Мы разрабатываем мобильные приложения более 5 лет и реализовали свыше 15 проектов с анимированной графикой (финтех, аналитические дашборды). Для работы используем современный стек: SwiftUI + Combine, Jetpack Compose + Coroutines, Flutter 3.x. Рекомендации Apple по анимации: используйте CAMediaTiming для синхронизации.
Как реализовать stagger-анимацию за 4 шага
- Инициализируйте
AnimationController(илиCADisplayLink). - Создайте массив задержек:
delay = index * intervalTime. - Для каждого элемента примените анимацию
TweenсCurvedAnimationиInterval. - Запустите общий контроллер — элементы начнут анимироваться последовательно.
Что такое downsampling и зачем он нужен?
Downsampling (прореживание точек) применяется при отрисовке больших наборов данных (500+ точек) для сохранения 60fps. [Алгоритм Рамера–Дугласа–Пекера](https://ru.wikipedia.org/wiki/Алгоритм_Рамера_—_Дугласа_—_Пекера) удаляет точки, лежащие на прямой в пределах заданного эпсилон, сохраняя визуальную форму графика.| Платформа | Механизм анимации | Ключевые классы |
|---|---|---|
| iOS | Core Animation (CALayer) | CABasicAnimation, CAKeyframeAnimation |
| Android | Canvas + ValueAnimator | ValueAnimator, ObjectAnimator |
| Flutter | AnimationController + Tween | AnimationController, Tween, Interval |
| React Native | Animated API | Animated.Value, Animated.timing |
Свяжитесь с нами, чтобы обсудить ваш график — оценим проект бесплатно. Закажите разработку анимации графика под ключ.







