Реализация параллакс-эффекта при скролле в мобильном приложении

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
Реализация параллакс-эффекта при скролле в мобильном приложении
Средний
от 1 дня до 3 дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    858
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    743
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1160
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    1034
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    968
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    562

Реализация параллакс-эффекта при скролле в мобильном приложении

Ваш заказчик просит параллакс при скролле? Первая реализация часто даёт дёрганье — FPS падает до 45 на устройствах вроде iPhone SE 2nd gen. Мы разобрались, как делать правильно на iOS и Android без просадок. Инженеры с 5+ лет опыта реализовали параллакс в 30+ проектах, и теперь делимся работающими подходами.

Параллакс создаёт визуальную глубину: фон движется медленнее контента. Но если привязать анимацию к main thread, получаем 40 FPS вместо 60. На старых Android-устройствах ситуация хуже — до 35 FPS. Мы гарантируем плавность на iOS 15+ и Android 11+.

Почему параллакс на main thread — зло?

Обработка скролла через делегаты (scrollViewDidScroll, OnScrollListener) блокирует UI-поток: каждый кадр — recalculation layout. Правильные подходы привязаны к draw pass: layoutSubviews в UIKit, graphicsLayer в Compose, MotionLayout на Android. Они не вызывают лишних measure/layout, экономя до 30% вычислительных ресурсов.

Как выбрать правильный API?

Выбор зависит от платформы и сложности. Ниже таблица с подходами и производительностью:

Платформа Подход Производительность Сложность
iOS UIKit layoutSubviews ~60 FPS Низкая
iOS SwiftUI GeometryReader / onScrollGeometryChange ~55–60 FPS Средняя
Android MotionLayout OnSwipe + ConstraintSet ~60 FPS Средняя
Android Compose graphicsLayer + derivedStateOf ~60 FPS Низкая

Дополнительно: при использовании MotionLayout FPS на Pixel 4 вырос с 40 до 60 (Рекомендации Google по анимации).

Как реализовать параллакс за 3 шага?

  1. Подготовка изображения: сделайте его выше контейнера на cellHeight * коэффициент (0.3) с каждой стороны — чтобы не было пустых краёв.
  2. Привязка к рендерингу: на iOS используйте layoutSubviews в ячейке, на Android — onDrawOver в ItemDecoration или graphicsLayer в Compose.
  3. Тестирование на слабых устройствах: проверьте FPS на iPhone SE 2nd gen (iOS) и Pixel 4 (Android). Если проседания более 5 FPS — уменьшите коэффициент до 0.2.

Примеры реализации

iOS: UIKit

override func layoutSubviews() {
    super.layoutSubviews()
    guard let superview = superview else { return }
    let cellFrameInSuperview = convert(bounds, to: superview)
    let parallaxOffset = cellFrameInSuperview.minY * 0.3
    heroImageView.transform = CGAffineTransform(translationX: 0, y: -parallaxOffset)
}

iOS: SwiftUI

ScrollView {
    LazyVStack {
        ForEach(items) { item in
            GeometryReader { geo in
                let offset = geo.frame(in: .global).minY
                Image(item.imageName)
                    .resizable()
                    .scaledToFill()
                    .frame(height: 250)
                    .offset(y: offset * 0.3)
                    .clipped()
            }
            .frame(height: 200)
        }
    }
}

Android: MotionLayout

<MotionScene>
    <Transition motion:constraintSetStart="@id/start" motion:constraintSetEnd="@id/end"
        motion:duration="1000">
        <OnSwipe
            motion:touchAnchorId="@id/nestedScrollView"
            motion:touchAnchorSide="top"
            motion:dragDirection="dragUp"
            motion:moveWhenScrollAtTop="true" />
    </Transition>
    <ConstraintSet android:id="@+id/start">
        <Constraint android:id="@+id/heroImage"
            android:translationY="0dp" ... />
    </ConstraintSet>
    <ConstraintSet android:id="@+id/end">
        <Constraint android:id="@+id/heroImage"
            android:translationY="-60dp" ... />
    </ConstraintSet>
</MotionScene>

Android: Compose

val listState = rememberLazyListState()

LazyColumn(state = listState) {
    itemsIndexed(items) { index, item ->
        val itemOffset by remember {
            derivedStateOf {
                val itemInfo = listState.layoutInfo.visibleItemsInfo.find { it.index == index }
                itemInfo?.let { (listState.layoutInfo.viewportEndOffset / 2f) - (it.offset + it.size / 2f) } ?: 0f
            }
        }
        Box(modifier = Modifier.height(200.dp).fillMaxWidth()) {
            Image(
                painter = painterResource(item.imageRes),
                contentDescription = null,
                modifier = Modifier
                    .fillMaxSize()
                    .graphicsLayer { translationY = itemOffset * 0.3f },
                contentScale = ContentScale.Crop
            )
        }
    }
}

Результаты замеров FPS

Устройство До оптимизации После оптимизации
iPhone SE 2nd gen 45 FPS 58 FPS
Pixel 4 40 FPS 60 FPS
Xiaomi Redmi 9T 35 FPS 57 FPS

Что входит в работу

  • Анализ текущего экрана и прототипирование параллакса.
  • Проектирование архитектуры анимации (выбор подхода под платформу).
  • Интеграция на iOS (UIKit/SwiftUI) и Android (MotionLayout/Compose).
  • Оптимизация: проверка FPS на реальных устройствах (iPhone SE, Pixel 4).
  • Предоставление исходного кода, документации и рекомендаций по дальнейшей поддержке.

Сроки

Параллакс для hero-изображения на одном экране: полдня. Параллакс в списке с множеством элементов (RecyclerView / LazyColumn / LazyVStack): 1–2 дня. Стоимость рассчитывается индивидуально.

Получите консультацию по вашему проекту — мы подберем оптимальную реализацию. Свяжитесь с нами для детальной оценки.

Примеры из проектовВ одном из e-commerce проектов мы заменили наивный параллакс на MotionLayout — FPS вырос с 40 до 60 на Android. В другом, для iOS, использовали UICollectionViewCompositionalLayout с параллаксом в ячейках — UI оставался плавным даже при скролле тысячи элементов.

Типичные ошибки при реализации параллакса

Первая ошибка — анимация на главном потоке. Использование scrollViewDidScroll для расчёта и применения offset напрямую блокирует UI-поток. На iPhone SE 2nd gen это снижает FPS с 60 до 40–45. Правильный подход: переносить трансформацию в layoutSubviews (UIKit) или graphicsLayer (Compose), где она выполняется на этапе рендеринга, а не layout.

Вторая ошибка — недостаточный размер изображения. Если высота изображения равна высоте контейнера, при скролле появятся тёмные края. Нужно добавить cellHeight × parallaxFactor сверху и снизу ещё на этапе подготовки ресурсов. Мы закладываем запас 30–40% от высоты ячейки.

Третья ошибка — отсутствие кэширования. Параллакс в LazyVStack или LazyColumn без кэширования изображений (Kingfisher, Coil, Glide) даёт просадки при прокрутке вверх — повторная загрузка занимает 200–500 мс. Рекомендуем настроить memory cache 100 МБ и disk cache 500 МБ.

Четвёртая ошибка — тестирование только на флагманах. iPhone 15 Pro и Pixel 9 справятся с любой реализацией. Проблемы проявляются на iPhone SE 2nd gen и Xiaomi Redmi 9T. Мы обязательно тестируем на трёх поколениях устройств перед финальной сдачей проекта.

Избегая этих ошибок, вы получите плавный параллакс без компромиссов по качеству.

Анимации в мобильных приложениях: Lottie, Rive, Spring и Reanimated

Мы сделали анимации для десятков проектов — от игровых интерфейсов до bank-grade приложений. Знаем, как заставить 120 fps работать даже на Android с ProGuard. Если анимация дёргается — проблема не в инструменте, а в выборе подхода. Ниже покажем, как мы выбираем между Lottie и Rive, почему Spring physics побеждает UIView.animate, и как Reanimated 3 выжимает 60 fps на старых устройствах. Получите консультацию по вашему проекту — оценим анимационный слой бесплатно.

Почему UIView.animate ломается на сложных сценариях

UIView.animate(withDuration:) и ObjectAnimator на Android — правильный выбор для простых переходов. Но как только анимация становится интерактивной (пользователь тянет элемент, скорость зависит от жеста), нужен другой подход.

На iOS для gesture-driven анимации правильный инструмент — UIViewPropertyAnimator. Он позволяет приостанавливать, обращать и модифицировать анимацию в процессе. Типичный кейс: bottom sheet, который следует за пальцем, продолжает движение с инерцией после отпускания и притягивается к ближайшей позиции. С UIView.animate это либо не работает совсем, либо требует ручной физики.

В SwiftUI withAnimation работает из коробки, но интерактивность ограничена — нет прямого аналога UIViewPropertyAnimator. Обходной путь: .gesture(DragGesture()) + @GestureState + явное вычисление позиции. Или уходим в SwiftUI Animations API с Animation.spring(duration:bounce:) из iOS 17.

Как React Native Reanimated обходит JS-мост

React Native Animated API выполняет анимации в JS thread — это источник джанка при загруженном bridge. Reanimated 3 решает проблему через worklets: функции, которые компилируются и выполняются прямо на UI thread без пересечения JS-моста.

Пример: parallax scroll header. На базовом Animated.Value при быстром скролле FPS падает до 40-45 на mid-range Android. На Reanimated с useAnimatedScrollHandler — стабильные 60 fps, потому что весь пересчёт позиции происходит на UI thread.

Reanimated 3 с useSharedValue, useAnimatedStyle и withSpring/withTiming — это текущий стандарт для анимаций в React Native. Gesture Handler v2 плотно интегрирован: useAnimatedGestureHandler заменяет PanResponder и тоже работает на UI thread.

Почему Lottie может снижать FPS на Android

Lottie экспортирует After Effects анимацию в JSON. На iOS с lottie-ios работает стабильно, но на Android при сложных эффектах (blur, частицы, градиенты) векторный рендеринг через Canvas приводит к просадкам до 30-40 fps. Решение — либо упрощать анимацию, либо использовать Rive с аппаратным рендерингом. Мы тестировали: Lottie-файл с размытием 5 МБ на Xiaomi Redmi Note 10 даёт 48 fps, аналогичная анимация в Rive (.riv 400 КБ) — 60 fps.

Lottie vs Rive: что выбрать для интерактивных интерфейсов

Оба инструмента решают задачу «дизайнер делает анимацию, разработчик добавляет файл». Но принципиально по-разному.

Подробное сравнение в таблице
Критерий Lottie Rive
Формат JSON векторная анимация Бинарный .riv
Интерактивность Нет (линейное воспроизведение) State Machine, реакции на ввод
Производительность Средняя (blur/частицы тяжелы) Аппаратный рендеринг Metal/OpenGL
Размер файла 2-5 МБ 200-500 КБ
Поддержка платформ iOS, Android, Web, Flutter, RN iOS, Android, Web, Flutter, RN

Выбор прост: статичная декоративная анимация (splash screen, onboarding иллюстрации) — Lottie. Интерактивные UI-элементы с состояниями — Rive. Например, кнопка с hover, pressed, loading, success — одна Rive-анимация с четырьмя состояниями против четырёх отдельных Lottie-файлов.

Дополнительно: Lottie — стандарт для размеченной векторной анимации, Rive — более гибкий инструмент с физикой и state machine.

Spring-физика и Hero transitions: как добиться естественности

Spring-анимация ощущается естественно потому что имитирует физику — массу, жёсткость и демпфирование. В SwiftUI: Animation.spring(response:dampingFraction:). В Android Compose: spring(dampingRatio = Spring.DampingRatioMediumBouncy).

Для Hero-переходов (элемент «перелетает» между экранами) на iOS используем UIViewControllerTransitioningDelegate + UIViewControllerAnimatedTransitioning. В SwiftUI с iOS 17 — matchedTransitionSource + navigationTransition(.zoom). На Flutter — Hero виджет, который работает из коробки.

Как избежать типичных ошибок в Hero transitions?

Анимация начинается нормально, но на целевом экране элемент «прыгает» в финальную позицию. Причина — AutoLayout constraints применяются до завершения анимации. Решение: layoutIfNeeded() в блоке анимации или использование transform вместо frame-изменений.

Что входит в работу: анимационный слой под ключ

  • Интеграция Lottie/Rive-файлов в дизайн-систему
  • Код gesture-driven переходов (bottom sheets, drawers, карусели)
  • Тестирование на реальных устройствах (iOS 15–17, Android 10–14)
  • Документация по анимациям (архитектура, ключи состояний)
  • Поддержка при обновлении дизайна (гарантия 30 дней)

У нас 5+ лет опыта в мобильной разработке, более 30 проектов с анимациями, сертифицированные iOS/Android разработчики.

Сроки выполнения

  • Базовые экранные переходы и микроинтеракции — 1 неделя.
  • Lottie/Rive интеграция с дизайн-системой — 3-5 дней после получения финальных файлов.
  • Кастомная gesture-driven интерактивность (sheet, drawer, карусель с физикой) — 1-2 недели.

Напишите нам — добавим анимации под ключ за 2 недели. Первая консультация бесплатно.