Android
ConstraintLayout
ScrollView
Mobile Development
UI Design

Android - how to make a scrollable constraintlayout?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

ConstraintLayout does not scroll by itself. If the content can grow beyond the screen, the usual solution is to place the ConstraintLayout inside a ScrollView or NestedScrollView, make the scrolling container the direct parent, and let the constrained content use wrap_content height.

The Correct Structure

The common pattern is:

xml
1<androidx.core.widget.NestedScrollView
2    android:layout_width="match_parent"
3    android:layout_height="match_parent"
4    android:fillViewport="true">
5
6    <androidx.constraintlayout.widget.ConstraintLayout
7        android:layout_width="match_parent"
8        android:layout_height="wrap_content">
9
10        <!-- child views here -->
11
12    </androidx.constraintlayout.widget.ConstraintLayout>
13</androidx.core.widget.NestedScrollView>

This works because:

  • the scroll container provides vertical scrolling
  • the ConstraintLayout measures to the full height of its content
  • 'fillViewport="true" helps short content still fill the screen nicely'

If you skip the scroll container, the layout will simply clip or compress content instead of scrolling.

Why wrap_content Matters

The inner ConstraintLayout should normally use android:layout_height="wrap_content". If you give it match_parent, the layout may only occupy the viewport height, which defeats the point of making the content area expandable.

A working example:

xml
1<androidx.core.widget.NestedScrollView
2    xmlns:android="http://schemas.android.com/apk/res/android"
3    xmlns:app="http://schemas.android.com/apk/res-auto"
4    android:layout_width="match_parent"
5    android:layout_height="match_parent"
6    android:fillViewport="true">
7
8    <androidx.constraintlayout.widget.ConstraintLayout
9        android:layout_width="match_parent"
10        android:layout_height="wrap_content"
11        android:padding="16dp">
12
13        <TextView
14            android:id="@+id/title"
15            android:layout_width="0dp"
16            android:layout_height="wrap_content"
17            android:text="Profile"
18            android:textSize="24sp"
19            app:layout_constraintTop_toTopOf="parent"
20            app:layout_constraintStart_toStartOf="parent"
21            app:layout_constraintEnd_toEndOf="parent" />
22
23        <TextView
24            android:id="@+id/body"
25            android:layout_width="0dp"
26            android:layout_height="wrap_content"
27            android:text="Long content goes here..."
28            app:layout_constraintTop_toBottomOf="@id/title"
29            app:layout_constraintStart_toStartOf="parent"
30            app:layout_constraintEnd_toEndOf="parent"
31            android:layout_marginTop="24dp" />
32
33    </androidx.constraintlayout.widget.ConstraintLayout>
34</androidx.core.widget.NestedScrollView>

Why NestedScrollView Is Often Better

ScrollView can work for simple cases, but NestedScrollView is usually safer in modern Android projects because it cooperates better with other nested scrolling components and coordinator-style layouts.

If your screen includes app bars, collapsing toolbars, or nested containers, NestedScrollView tends to integrate more cleanly.

Constraints Still Need to Be Valid

Placing ConstraintLayout inside a scrolling parent does not change how constraints work. Every child still needs valid vertical constraints so the layout can compute its total height.

Typical mistakes include:

  • child views constrained only horizontally
  • a final view that is not constrained downward from the previous content
  • using 0dp heights without the proper top and bottom constraints

If the content height is ambiguous, the scroll container cannot measure the full scrollable area correctly.

When Not to Use This Pattern

If the screen is essentially a long list of repeated rows, RecyclerView is usually better than one giant scrolling ConstraintLayout. A scrollable ConstraintLayout is appropriate for:

  • forms
  • profile screens
  • settings screens
  • mixed static content

It is not ideal for hundreds of repeated items because the whole view tree is still inflated at once.

Programmatic Setup

If you build the layout in code, the principle is the same:

kotlin
1val scroll = NestedScrollView(this).apply {
2    layoutParams = ViewGroup.LayoutParams(
3        ViewGroup.LayoutParams.MATCH_PARENT,
4        ViewGroup.LayoutParams.MATCH_PARENT
5    )
6    isFillViewport = true
7}
8
9val content = ConstraintLayout(this).apply {
10    layoutParams = ViewGroup.LayoutParams(
11        ViewGroup.LayoutParams.MATCH_PARENT,
12        ViewGroup.LayoutParams.WRAP_CONTENT
13    )
14}
15
16scroll.addView(content)

The scroll container wraps the content container. ConstraintLayout is still the content layout, not the scrolling mechanism.

Common Pitfalls

  • Expecting ConstraintLayout itself to scroll without wrapping it in ScrollView or NestedScrollView.
  • Giving the inner ConstraintLayout a height of match_parent instead of wrap_content, which prevents it from expanding with content.
  • Forgetting fillViewport="true" and then getting awkward empty space behavior on short screens.
  • Leaving child views under-constrained so the layout cannot calculate its full content height correctly.
  • Using one huge scrollable layout for data that really belongs in a RecyclerView.

Summary

  • 'ConstraintLayout becomes scrollable by placing it inside ScrollView or, more commonly, NestedScrollView.'
  • The inner ConstraintLayout should usually have wrap_content height.
  • 'fillViewport="true" improves behavior when the content is shorter than the screen.'
  • Valid child constraints are still required so the scrollable content height can be measured correctly.
  • For repeated large datasets, use RecyclerView instead of one oversized scrolling ConstraintLayout.

Course illustration
Course illustration

All Rights Reserved.