Mobile Development 14 min read

Analyzing and Fixing TextView Marquee Reset Issue on Android 6.0+

The article shows how to diagnose the Android 6.0+ TextView marquee jump caused by a button’s setText triggering requestLayout and onMeasure, and fixes it by giving the button a fixed size instead of wrap_content, illustrating a systematic source‑code analysis and debugging workflow for UI issues.

vivo Internet Technology
vivo Internet Technology
vivo Internet Technology
Analyzing and Fixing TextView Marquee Reset Issue on Android 6.0+

This article explains how to diagnose and solve the problem where a TextView marquee animation resets (jumps) after clicking the "Add to Cart" button on Android 6.0 and above.

Background : The author notes that developers often lack time to read source code and may get stuck when a UI issue appears. The article uses a concrete problem to demonstrate a systematic source‑code analysis approach.

Problem description : On Android 6.0+ the TextView with android:ellipsize="marquee" and android:singleLine="true" exhibits a jump when the button is pressed. The animation restarts from the beginning each time.

Preparation : The author prepared the Android source code, created an Android Studio project, and added a demo that reproduces the issue.

Sample Java code (MainActivity) :

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    findViewById(R.id.show_tv).setSelected(true);
    final TextView changeTv = findViewById(R.id.change_tv);
    changeTv.setText(getString(R.string.shopping_count, mNum));
    findViewById(R.id.click_tv).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mNum++;
            changeTv.setText(getString(R.string.shopping_count, mNum));
        }
    });
}

Sample XML layout :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.workshop.textview.MyTextView
        android:id="@+id/show_tv"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_alignParentTop="true"
        android:layout_marginTop="30dp"
        android:ellipsize="marquee"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:marqueeRepeatLimit="marquee_forever"
        android:padding="5dp"
        android:scrollHorizontally="true"
        android:textColor="@android:color/holo_blue_bright"
        android:singleLine="true"
        android:text="!!!广告!!!vivo S7手机将不惧距离与光线的限制,带来全场景化自拍体验,刷新了5G时代的自拍旗舰标准"
        android:textSize="24sp" />

    <TextView
        android:id="@+id/change_tv"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/shopping_count"
        android:textColor="@android:color/holo_orange_dark"
        android:textSize="28sp" />

    <TextView
        android:id="@+id/click_tv"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="30dp"
        android:background="@android:color/darker_gray"
        android:padding="5dp"
        android:singleLine="true"
        android:text="添加购物车"
        android:textColor="@android:color/background_dark"
        android:textSize="24sp"
        android:textStyle="bold" />

</RelativeLayout>

Analysis steps :

Search for the marquee implementation in Android source (e.g., startMarquee() ).

Identify that onDraw() calls startMarquee() when singleLine=true and ellipsize=marquee .

Trace the Marquee inner class: initialization, start() , setting of scroll variables, and invalidate() calls.

Understand the role of Choreographer – it provides per‑frame callbacks ( postFrameCallback ) that drive the marquee animation.

Examine the Marquee Tick method: calculates mPixelsPerMs , computes deltaMs , updates mScroll , caps it at mMaxScroll , and calls invalidate() .

Observe that the animation resets when mScroll is set back to zero, which happens when TextView.onMeasure() is triggered.

Root cause : Clicking the "Add to Cart" button calls setText() on the numeric TextView. setText() internally calls requestLayout() , which forces a new measurement pass. During this pass onMeasure() resets the marquee’s scroll position, causing the animation to restart.

Solution : Change the layout parameter of the button (or any view that triggers requestLayout() ) from wrap_content to a fixed size (e.g., match_parent or a specific dp value). This prevents requestLayout() from being invoked on each click, stopping the marquee reset.

After modifying the button’s width/height, the marquee runs continuously without jumping.

Conclusion : The article demonstrates a systematic debugging workflow for Android UI issues: (1) locate relevant source code, (2) draw flow diagrams, (3) hypothesize causes, (4) verify with breakpoints, and (5) apply a minimal layout change to fix the problem. It also highlights the importance of understanding Android’s view lifecycle, Marquee implementation, and Choreographer timing.

debugginganimationlayoutAndroidChoreographerTextViewmarquee
vivo Internet Technology
Written by

vivo Internet Technology

Sharing practical vivo Internet technology insights and salon events, plus the latest industry news and hot conferences.

0 followers
Reader feedback

How this landed with the community

login 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.