Реализация анимации сворачивания/раскрытия (Collapsing Toolbar) в мобильном приложении

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

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

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

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 1735 услуг
Реализация анимации сворачивания/раскрытия (Collapsing Toolbar) в мобильном приложении
Средний
от 1 дня до 3 дней
Часто задаваемые вопросы

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

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

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

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    495

Реализация анимации сворачивания/раскрытия (Collapsing Toolbar) в мобильном приложении

Collapsing Toolbar — шапка экрана, которая сворачивается при скролле контента вниз. В развёрнутом виде — большое изображение и крупный заголовок, при скролле — компактная навигационная панель. iOS Contacts app, Android Play Store карточка приложения — оба используют этот паттерн.

Сложность: нужно синхронизировать scroll position с размером toolbar, позицией заголовка, opacity элементов. И сделать это без скачков на 120 Hz дисплеях.

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
}

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.

Сроки

Collapsing toolbar через стандартный CollapsingToolbarLayout или LargeTopAppBar: полдня. Кастомный с изображением, parallax и несколькими анимируемыми элементами: 1–2 дня. Стоимость рассчитывается индивидуально.