A parallax header effect creates a dynamic visual experience where the header image moves at a slower rate than the list content when scrolling. This pattern, popularized by apps like Spotify, draws user attention and enhances perceived performance.
In Android, this effect can be achieved by combining a ListView with a header view and listening to scroll changes to adjust the header’s position or scaling accordingly.
What Is a Parallax Header?
A parallax header refers to a scrolling animation where the background moves at a different speed relative to the foreground content. In the context of a ListView, this typically means:
- A header image view placed above the list
- As the user scrolls up, the image moves slower than the list items
- Optionally the image can scale or fade out for more dramatic effect
The key visual cue is that the header has its own scroll offset separate from the list content.
When to Use Parallax with ListView
Use this pattern when:
- You want to create visual depth in your UI
- Your design has a large image above a list (e.g., profile header, cover image)
- You want your app to feel more like a native experience with fluid animation
- Your min SDK supports View scrolling events (API ≥ 14+)
The effect should enhance UX, not distract from content.
Layout Setup
To make parallax work with a ListView, you need:
- A container layout (usually
FrameLayout) - An
ImageViewfor the header - A placeholder view to pad the top of the
ListView - The
ListViewitself
Example layout (activity_main.xml):
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Parallax header image -->
<ImageView
android:id="@+id/headerImage"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop"
android:src="@drawable/header_image"/>
<!-- List background placeholder -->
<View
android:id="@+id/listBackground"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@color/backgroundColor"/>
<!-- Main ListView -->
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingTop="200dp"/>
</FrameLayout>
In this layout:
- The
ImageViewis placed at the top - The
ListView’s top padding matches the header image height - A background View ensures the list items don’t render transparently over the image
Scroll Listener Logic
To create the parallax effect, we respond to scroll changes and adjust the header image position or scale. In your Activity:
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {}
@Override
public void onScroll(AbsListView view,
int firstVisibleItem,
int visibleItemCount,
int totalItemCount) {
// Get the top of the first item (header placeholder)
View firstChild = view.getChildAt(0);
int scrollY = (firstChild == null) ? 0 : -firstChild.getTop();
// Move the header image at half scroll speed
headerImage.setTranslationY(scrollY * 0.5f);
}
});
Here:
- We measure how far the list has scrolled vertically
- We offset the header image at a slower rate (e.g., half speed) for the parallax effect
This simple calculation creates a smooth visual experience.
Scaling & Fading Options
For an enhanced parallax:
float ratio = Math.min(1f, scrollY / (float)headerHeight);
headerImage.setScaleX(1f - (ratio * 0.2f));
headerImage.setScaleY(1f - (ratio * 0.2f));
headerImage.setAlpha(1f - ratio);
This adds:
- Scale shrink as the user scrolls
- Fade out effect for the header image
Use small scale ratios to avoid abrupt visual changes.
Sticky Title or Section Header
If you want a sticky header (a view that stays pinned at the top), you can:
- Add a dedicated view (TextView, Toolbar, etc.)
- Adjust its visibility based on scroll position
Example:
if (scrollY > headerHeight) {
stickyHeader.setVisibility(View.VISIBLE);
} else {
stickyHeader.setVisibility(View.GONE);
}
This toggles visibility once scroll passes header height.
Best Practices
From real Android engineering experience:
- Use
RecyclerViewwithAppBarLayoutandCollapsingToolbarLayoutfor modern parallax & scrolling effects — easier to maintain and robust. - Avoid heavy image processing on the UI thread
- For simpler effects on legacy devices, ListView parallax works fine
- Always test on multiple screen sizes
Common Challenges and Fixes
Header jumps suddenly
✔ Ensure the list top padding matches the header height exactly
Performance stutters
✔ Move scroll calculations to a more efficient callback or use translation properties
Image artifact on device rotation
✔ Use proper view binding and handle layout changes in Activity
Summary
Implementing a parallax header with ListView enhances UI depth and creates a modern feel even in legacy list implementations. Key steps include:
- Placing a header ImageView above a padded ListView
- Listening to scroll events
- Translating or scaling the image at a slower rate
This technique enriches visual storytelling without complicating the core list logic.


