Mobile Development 13 min read

Why Does My ListView Inside a Dialog Won’t Scroll? Understanding MeasureSpec and Fixing the Bug

An Android junior developer discovers a dialog‑embedded ListView that fails to scroll, investigates the custom ListViewForScrollView implementation, learns how MeasureSpec and onMeasure work, and resolves the issue by replacing the custom view with a standard ListView.

Shixingshengxian Technology Team
Shixingshengxian Technology Team
Shixingshengxian Technology Team
Why Does My ListView Inside a Dialog Won’t Scroll? Understanding MeasureSpec and Fixing the Bug

Production Incident: A Dialog Layout Cut Off the Bottom

A junior Android developer, Xiao Zhang, was confident his code was bug‑free until a tester reproduced an online bug where a dialog’s bottom service popup was truncated.

Reproducing the Scene

The screenshot shows the dialog’s lower part being clipped, indicating the dialog’s content is not fully displayed.

Root Cause Analysis

Initially Xiao Zhang blamed the dialog’s height, but the XML layout revealed a custom ListViewForScrollView inside a RelativeLayout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- omitted unrelated code -->
    <com.xx.ListViewForScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="18dip"
        android:layout_marginRight="20dp"
        android:layout_marginBottom="48dp"
        android:divider="@null" />
</RelativeLayout>

Inspecting the custom view’s source shows it merely overrides onMeasure to force an AT_MOST mode with a very large size:

public class ListViewForScrollView extends ListView {
    public ListViewForScrollView(Context context) { super(context); }
    public ListViewForScrollView(Context context, AttributeSet attrs) { super(context, attrs); }
    public ListViewForScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }
}

The developer wondered why the ListView could not scroll despite inheriting from ListView. He dug deeper into Android’s measurement process.

Understanding MeasureSpec

Every view goes through onMeasure, onDraw, and onLayout. The two parameters, widthMeasureSpec and heightMeasureSpec, are 32‑bit ints where the high two bits encode the mode (UNSPECIFIED, EXACTLY, AT_MOST) and the low 30 bits encode the size. The parent view supplies these specs, but a child can influence its final size.

The three modes are:

UNSPECIFIED : No constraints from the parent.

EXACTLY : The parent dictates an exact size.

AT_MOST : The child may be any size up to the specified maximum.

The static method ViewGroup.getChildMeasureSpec combines the parent spec with the child’s layout parameters to produce an appropriate child spec.

public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
    int specMode = MeasureSpec.getMode(spec);
    int specSize = MeasureSpec.getSize(spec);
    int size = Math.max(0, specSize - padding);
    int resultSize = 0;
    int resultMode = 0;
    switch (specMode) {
        case MeasureSpec.EXACTLY:
            if (childDimension >= 0) { resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; }
            else if (childDimension == LayoutParams.MATCH_PARENT) { resultSize = size; resultMode = MeasureSpec.EXACTLY; }
            else if (childDimension == LayoutParams.WRAP_CONTENT) { resultSize = size; resultMode = MeasureSpec.AT_MOST; }
            break;
        case MeasureSpec.AT_MOST:
            if (childDimension >= 0) { resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; }
            else if (childDimension == LayoutParams.MATCH_PARENT) { resultSize = size; resultMode = MeasureSpec.AT_MOST; }
            else if (childDimension == LayoutParams.WRAP_CONTENT) { resultSize = size; resultMode = MeasureSpec.AT_MOST; }
            break;
        case MeasureSpec.UNSPECIFIED:
            if (childDimension >= 0) { resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; }
            else if (childDimension == LayoutParams.MATCH_PARENT) { resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; }
            else if (childDimension == LayoutParams.WRAP_CONTENT) { resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; }
            break;
    }
    return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}

Thus a view’s final size is determined by both its parent’s constraints and its own layout parameters.

Fixing the Problem

Because ListViewForScrollView forces a massive height (≈ 536 870 911), the ListView occupies the entire dialog space, leaving no room for scrolling. Replacing the custom view with a regular ListView restores normal scrolling behavior, and the dialog displays correctly.

View measurement diagram
View measurement diagram

Key takeaways:

Understand the view drawing pipeline (measure, draw, layout).

Know how MeasureSpec influences view size.

Fully grasp the behavior of custom views before using them.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AndroidListViewCustomViewMeasureSpecUI Bug
Shixingshengxian Technology Team
Written by

Shixingshengxian Technology Team

Shixingshengxian Technology Team

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.