ScrollView in Android: A Practical Guide for 2026

Last month I shipped a settings screen that looked perfect on my test device and immediately broke on a smaller phone. The bottom buttons were hidden, and users had no way to reach them. The fix was a single view, but it reminded me why ScrollView still matters in 2026: it is the simplest way to make a long screen feel natural in the classic Android View system. I still reach for it when building forms, long help pages, or small dashboards where the content length is unknown. It turned a one-size layout into something that adapts to real screens.

If you have ever stacked a bunch of views in a LinearLayout and wondered why the screen clips, ScrollView is the missing piece. I will show you the mental model I use, how I set it up in XML and Kotlin, the attributes that actually change behavior, and the mistakes that create janky scrolling. I will also cover when I avoid ScrollView entirely, especially in a world where Compose and RecyclerView are often the better fit. By the end you should be able to choose the right scrolling container, wire it cleanly, and keep your UI fast and predictable. ScrollView is not flashy, but its predictability is exactly why I trust it in production.

Mental Model: ScrollView as a Viewport

ScrollView is a ViewGroup that acts like a window onto a taller piece of content. I picture it as a clipboard with a long sheet of paper: you only see the part inside the frame, and your finger moves the sheet up and down. That mental model explains its key rules.

First, a ScrollView can have only one direct child. If you need multiple views, you wrap them in a container such as LinearLayout, ConstraintLayout, or another ViewGroup. The ScrollView scrolls its single child by changing its scroll position; it does not move every child individually. Second, it supports vertical scrolling only. If you need horizontal motion, you should use HorizontalScrollView or a horizontal RecyclerView for lists. Third, it does not recycle its children. Everything inside the child is inflated, measured, and laid out, which is perfect for a small form but expensive for hundreds of rows.

In touch handling, ScrollView intercepts vertical drag gestures so the content moves as a single unit. If a child needs to handle gestures, like a map or a chart, I call requestDisallowInterceptTouchEvent(true) to let that child take over during interaction. For nested layouts with collapsing toolbars, I reach for NestedScrollView because it cooperates with CoordinatorLayout and AppBarLayout. The important idea is this: ScrollView is a simple viewport for a single tall child, not a general list component.

There is also a measurement detail that saves me a lot of debugging time. ScrollView measures its child with an unspecified height. That means a child with layoutheight=‘matchparent‘ behaves more like wrap_content, because the parent is saying, in effect, I do not know how tall you need to be. When you remember that, the strange cases start to make sense: a child that refuses to fill space, or a button that floats in the middle of the screen when the content is short. The fix is almost always to use fillViewport or to pin the ScrollView between other views with proper constraints.

I also keep the gesture stack in mind. ScrollView wants to own vertical drags. If you put something like a ViewPager2 or a map inside it, the two are going to compete. That is where nested scrolling and intercept rules matter, and where I start considering alternative layouts. But as long as the screen is simple and the content is bounded, ScrollView is the most reliable option in the View system.

Building a Simple ScrollView Layout (XML + Kotlin)

When the screen is mostly static, I often use ScrollView as the root so scrolling logic is obvious and constraints stay simple. The example below is complete and runnable, and it forces the content to exceed the screen height.

  • Create an Empty Activity project in Android Studio and choose Kotlin or Java.
  • Replace activity_main.xml with the layout below.
  • Run the app on a smaller device or emulator so the body text extends past the bottom.

XML:

<ScrollView xmlns:android='http://schemas.android.com/apk/res/android'

android:id=‘@+id/scroll‘

android:layoutwidth=‘matchparent‘

android:layoutheight=‘matchparent‘

android:fillViewport=‘true‘

android:padding=‘16dp‘

android:clipToPadding=‘false‘

android:scrollbars=‘vertical‘

android:overScrollMode=‘ifContentScrolls‘>

<LinearLayout

android:id=‘@+id/content‘

android:layoutwidth=‘matchparent‘

android:layoutheight=‘wrapcontent‘

android:orientation=‘vertical‘>

<TextView

android:id=‘@+id/title‘

android:layoutwidth=‘matchparent‘

android:layoutheight=‘wrapcontent‘

android:text=‘Settings‘

android:textSize=‘24sp‘

android:textStyle=‘bold‘ />

<TextView

android:id=‘@+id/subtitle‘

android:layoutwidth=‘matchparent‘

android:layoutheight=‘wrapcontent‘

android:layout_marginTop=‘8dp‘

android:text=‘These are real options that keep growing as the app grows.‘

android:textSize=‘14sp‘ />

<View

android:layoutwidth=‘matchparent‘

android:layout_height=‘16dp‘ />

<Switch

android:id=‘@+id/switch_notifications‘

android:layoutwidth=‘matchparent‘

android:layoutheight=‘wrapcontent‘

android:text=‘Notifications‘ />

<Switch

android:id=‘@+id/switch_location‘

android:layoutwidth=‘matchparent‘

android:layoutheight=‘wrapcontent‘

android:text=‘Location access‘ />

<CheckBox

android:id=‘@+id/check_beta‘

android:layoutwidth=‘matchparent‘

android:layoutheight=‘wrapcontent‘

android:text=‘Join beta program‘ />

<TextView

android:layoutwidth=‘matchparent‘

android:layoutheight=‘wrapcontent‘

android:layout_marginTop=‘12dp‘

android:text=‘About‘

android:textStyle=‘bold‘ />

<TextView

android:id=‘@+id/body‘

android:layoutwidth=‘matchparent‘

android:layoutheight=‘wrapcontent‘

android:layout_marginTop=‘8dp‘

android:lineSpacingExtra=‘4dp‘

android:text=‘This screen is intentionally long to demonstrate scrolling. Add more text here to exceed the device height and verify that you can still reach the call to action at the bottom.‘ />

<View

android:layoutwidth=‘matchparent‘

android:layout_height=‘24dp‘ />

<Button

android:id=‘@+id/cta‘

android:layoutwidth=‘matchparent‘

android:layoutheight=‘wrapcontent‘

android:text=‘Save changes‘ />

<View

android:layoutwidth=‘matchparent‘

android:layout_height=‘24dp‘ />

Kotlin:

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

val scroll = findViewById(R.id.scroll)

val cta = findViewById

Scroll to Top