Collapsing toolbar animation in mobile app

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1 servicesAll 1735 services
Collapsing toolbar animation in mobile app
Medium
from 1 business day to 3 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

Collapsing Toolbar Animation Implementation in Mobile Apps

A Collapsing Toolbar is a header that contracts as content scrolls downward. When expanded, it displays a large image and prominent title; as content scrolls, it becomes a compact navigation panel. Both iOS Contacts app and Android Play Store use this pattern.

The challenge lies in synchronizing scroll position with toolbar size, title position, and element opacity. All must work smoothly on 120 Hz displays without stuttering.

Android: CollapsingToolbarLayout

The declarative approach uses CollapsingToolbarLayout within 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" on ImageView creates parallax during collapse. "pin" on Toolbar pins it when fully collapsed. app:layout_scrollFlags="scroll|exitUntilCollapsed" causes AppBar to scroll with content until reaching minimum height (Toolbar height).

contentScrim is a color or drawable that appears over the image as it collapses, animating smoothly.

Custom logic uses AppBarLayout.OnOffsetChangedListener:

appBarLayout.addOnOffsetChangedListener { appBar, offset ->
    val progress = (-offset).toFloat() / appBar.totalScrollRange.toFloat()
    // progress: 0f = expanded, 1f = collapsed
    avatarView.alpha = 1f - (progress * 2).coerceIn(0f, 1f)
    subtitleView.scaleX = 1f - progress * 0.3f
    subtitleView.scaleY = subtitleView.scaleX
}

Jetpack Compose: TopAppBarScrollBehavior

Compose Material3 provides LargeTopAppBar with TopAppBarDefaults.exitUntilCollapsedScrollBehavior():

val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()

Scaffold(
    topBar = {
        LargeTopAppBar(
            title = { Text("Title") },
            scrollBehavior = scrollBehavior,
            colors = TopAppBarDefaults.largeTopAppBarColors(
                containerColor = MaterialTheme.colorScheme.surface,
                scrolledContainerColor = MaterialTheme.colorScheme.surface,
            )
        )
    },
    modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
) { padding ->
    LazyColumn(contentPadding = padding) { ... }
}

For custom collapsing toolbar with images (LargeTopAppBar doesn't support photos in the header), build using 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 is the key value controlling image alpha, title scale, and visibility of additional elements.

iOS: UIScrollViewDelegate + Auto Layout

The classic iOS approach uses scrollViewDidScroll:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let offset = scrollView.contentOffset.y
    let maxOffset: CGFloat = 200 // expanded header height

    if offset < 0 {
        // Overscroll downward—stretch image
        headerHeightConstraint.constant = 250 - offset
        headerImageView.transform = .identity
    } else {
        let progress = min(offset / maxOffset, 1.0)
        headerHeightConstraint.constant = max(250 - offset, 56)

        // Fade out image
        headerImageView.alpha = 1 - progress

        // Title appears in nav bar
        navigationItem.title = progress > 0.9 ? screenTitle : ""
    }

    // No layoutIfNeeded in animation—direct constraint change; next layout pass applies it
}

Changing constraints directly in scrollViewDidScroll without animation is correct; layout pass occurs at the next CADisplayLink frame. Calling layoutIfNeeded() here would create recursion.

In SwiftUI, use ScrollView + GeometryReader to track scroll position and @State for header height management.

Timeline

Collapsing toolbar using standard CollapsingToolbarLayout or LargeTopAppBar: half a day. Custom with image, parallax, and multiple animated elements: 1–2 days. Cost is calculated individually.