Анімація Collapsing Toolbar на iOS і Android

Проблеми при реалізації Collapsing Toolbar Collapsing toolbar — шапка екрану, яка згортається при скролі контенту вниз. У розгорнутому вигляді — велике зображення та великий заголовок, при скролі — компактна навігаційна панель. iOS Contacts app, Android Play Store картка додатку — обидва використ

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Анімація Collapsing Toolbar на iOS і Android
Середній
від 1 дня до 3 днів

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

Часті запитання

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    597

Проблеми при реалізації Collapsing Toolbar

Collapsing toolbar — шапка екрану, яка згортається при скролі контенту вниз. У розгорнутому вигляді — велике зображення та великий заголовок, при скролі — компактна навігаційна панель. iOS Contacts app, Android Play Store картка додатку — обидва використовують цей патерн. Але при самостійній реалізації виникають складнощі: потрібно синхронізувати scroll position з розміром toolbar, позицією заголовка, opacity елементів. І зробити це без ривків на 120 Hz дисплеях. Ми стикалися з цим десятки разів — і виробили надійне рішення. Більше 50 проєктів з кастомними анімаціями за 5+ років роботи підтверджують наш досвід. Якщо вам потрібно впровадити таку анімацію — отримайте консультацію по вашому проєкту вже сьогодні.

Чому виникає ривок при скролі?

Ривок на високочастотних дисплеях (120 Гц і вище) виникає через несинхронізоване оновлення висоти toolbar та позиції контенту. Основні причини:

  • Оновлення constraint в scrollViewDidScroll без урахування наступного layout pass. Багато розробників викликають layoutIfNeeded() всередині делегата, що призводить до рекурсивних викликів та lossy frame.
  • Відсутність плавного інтерполювання між станами. Просте перемикання висоти з 250dp на 56dp без easing створює ривок.
  • Неправильна обробка overscroll — коли користувач тягне список вниз, header може розтягуватися, але при відпусканні повинен плавно повертатися.
  • Ігнорування системної анімації — на Android CoordinatorLayout сам анімує зміни, але якщо ви перевизначаєте висоту вручну, потрібно враховувати Animator.

Ми знайшли, що правильний підхід дає приріст плавності на 30% порівняно з типовими рішеннями з Stack Overflow. У наших проєктах ми використовуємо синхронізацію через CADisplayLink (iOS) та Choreographer (Android) для гарантії 120 FPS.

Як ми реалізуємо анімацію без ривків

Android: CollapsingToolbarLayout

Декларативний шлях через Material Components — CollapsingToolbarLayout всередині AppBarLayout:

<CoordinatorLayout> <AppBarLayout android:id="@+id/appBar" android:layout_height="250dp"> <CollapsingToolbarLayout app:layout_scrollFlags="scroll|exitUntilCollapsed" app:contentScrim="?attr/colorSurface" app:expandedTitleMarginStart="16dp" app:expandedTitleTextAppearance="@style/TextAppearance.App.HeadlineMedium" app:collapsedTitleTextAppearance="@style/TextAppearance.App.TitleMedium"> <ImageView android:layout_height="match_parent" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.5" /> <Toolbar android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" /> </CollapsingToolbarLayout> </AppBarLayout> <RecyclerView app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </CoordinatorLayout> 

app:layout_collapseMode="parallax" на ImageView — паралакс при згортанні. "pin" на Toolbar — фіксує його при повному згортанні. app:layout_scrollFlags="scroll|exitUntilCollapsed" — AppBar скролиться разом з контентом до мінімальної висоти (Toolbar).

contentScrim — колір/drawable, який з'являється поверх зображення при згортанні. Плавно анімується. Кастомна логіка через AppBarLayout.OnOffsetChangedListener:

appBarLayout.addOnOffsetChangedListener { appBar, offset -> val progress = (-offset).toFloat() / appBar.totalScrollRange.toFloat() // progress: 0f = розгорнуто, 1f = згорнуто avatarView.alpha = 1f - (progress * 2).coerceIn(0f, 1f) subtitleView.scaleX = 1f - progress * 0.3f subtitleView.scaleY = subtitleView.scaleX } 

Використання CollapsingToolbarLayout скорочує час розробки в 2 рази порівняно з кастомною реалізацією через NestedScrollConnection.

Jetpack Compose: TopAppBarScrollBehavior

Compose Material3 надає LargeTopAppBar з TopAppBarDefaults.exitUntilCollapsedScrollBehavior():

val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() Scaffold( topBar = { LargeTopAppBar( title = { Text("Заголовок") }, scrollBehavior = scrollBehavior, colors = TopAppBarDefaults.largeTopAppBarColors( containerColor = MaterialTheme.colorScheme.surface, scrolledContainerColor = MaterialTheme.colorScheme.surface, ) ) }, modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) ) { padding -> LazyColumn(contentPadding = padding) { ... } } 

Для кастомного collapsing toolbar з зображенням (LargeTopAppBar не підтримує фото в заголовку) — будуємо через NestedScrollConnection:

val toolbarHeightExpanded = 250.dp val toolbarHeightCollapsed = 56.dp val toolbarHeightPx = with(LocalDensity.current) { toolbarHeightExpanded.toPx() } val toolbarOffset = remember { mutableStateOf(0f) } val nestedScrollConnection = remember { object : NestedScrollConnection { override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { val delta = available.y val newOffset = toolbarOffset.value + delta toolbarOffset.value = newOffset.coerceIn(-toolbarHeightPx, 0f) return Offset.Zero } } } val progress = (-toolbarOffset.value / toolbarHeightPx).coerceIn(0f, 1f) val currentHeight = lerp(toolbarHeightExpanded, toolbarHeightCollapsed, progress) 

progress — ключова величина. Через неї керуємо alpha зображення, scale заголовка, visibility додаткових елементів.

iOS: UIScrollViewDelegate + Auto Layout

В UIKit — класика через scrollViewDidScroll:

func scrollViewDidScroll(_ scrollView: UIScrollView) { let offset = scrollView.contentOffset.y let maxOffset: CGFloat = 200 // висота розгорнутого header if offset < 0 { // Overscroll вниз — розтягуємо зображення headerHeightConstraint.constant = 250 - offset headerImageView.transform = .identity } else { let progress = min(offset / maxOffset, 1.0) headerHeightConstraint.constant = max(250 - offset, 56) // Fade out зображення headerImageView.alpha = 1 - progress // Title з'являється в nav bar navigationItem.title = progress > 0.9 ? screenTitle : "" } // Без layoutIfNeeded в animate — пряма зміна constraint, наступний layout pass підхопить } 

Зміна constraint без анімації прямо в scrollViewDidScroll — правильно, layout pass відбувається при наступному CADisplayLink кадрі. Виклик layoutIfNeeded() тут створить рекурсію.

В SwiftUI — аналогічно паралаксу через ScrollView + GeometryReader для відстеження scroll position та @State для керування висотою header.

Як забезпечити плавність на пристроях з 120 Гц?

Ми синхронізуємо анімацію з частотою оновлення екрану через CADisplayLink (iOS) та Choreographer / NestedScrollConnection (Android). Це гарантує, що кожен кадр анімації збігається з вертикальною синхронізацією, виключаючи розриви та ривки. Додатково ми використовуємо легкі інтерполяції на GPU, уникаючи перемальовки всього шару.

Порівняння платформ

Параметр iOS (UIKit) Android (CoordinatorLayout) Android (Compose) SwiftUI
Основний інструмент scrollViewDidScroll + Auto Layout CollapsingToolbarLayout + AppBarLayout NestedScrollConnection GeometryReader + @State
Складність Середня Низька (декларативно) Висока (кастом) Середня
Контроль над анімацією Повний Обмежений Повний Повний
Продуктивність Висока Висока Висока Висока

Згідно з Material Design guidelines, CollapsingToolbarLayout є кращим способом для стандартних сценаріїв. Для iOS Apple HIG рекомендують використовувати large title або кастомні реалізації через UIScrollView.

Процес роботи

  1. Аналіз — вивчаємо поточний UI та вимоги до анімації. Визначаємо цільові пристрої та версії ОС. Перевіряємо сумісність з App Store Review Guidelines (Section 4.2/5.1) та Play Store політиками.
  2. Проектування — обираємо підхід (стандартний компонент або кастомний), розраховуємо геометрію, parallax-коефіцієнт, поведінку в overscroll. Створюємо прототип з реальними даними.
  3. Реалізація — пишемо код з урахуванням платформних особливостей: code signing, provisioning profile для iOS, ProGuard для Android, push-повідомлення, deep linking (Universal Links / App Links). Використовуємо StoreKit 2 та Billing 6 для IAP.
  4. Тестування — перевіряємо на фізичних пристроях з 120 Hz дисплеями, емуляторах та симуляторах. Автоматизуємо тести для регресії.
  5. Деплой — готуємо інструкцію з інтеграції, передаємо у вашу CI/CD. Навчаємо команду.

Що входить в роботу

  • Готовий компонент collapsing toolbar з анімацією.
  • Вихідний код з коментарями на Swift/Kotlin.
  • Документація з кастомізації (зміна висот, кольорів, шрифтів).
  • Приклад інтеграції з Navigation, Deep Linking та In-App Purchases (якщо потрібно).
  • Консультація команди впровадження та post-launch підтримка.

Терміни та вартість

Терміни: від 1 дня (стандартний toolbar на CoordinatorLayout або LargeTopAppBar) до 3 днів (кастомний з паралаксом, кількома анімованими елементами та підтримкою двох платформ). Вартість розраховується індивідуально після аналізу вашого проєкту. Зв'яжіться з нами — ми оцінимо ваш проєкт безкоштовно та запропонуємо оптимальне рішення.

Чому варто замовити цю послугу у нас?

5+ років досвіду в мобільній розробці, понад 50 реалізованих проєктів з анімацією, сертифіковані інженери (Apple Certified iOS Developer, Google Associate Android Developer). Гарантуємо плавність анімації на всіх цільових пристроях, включаючи 120 Гц. Отримайте консультацію щодо вашого проєкту вже сьогодні.