70

I am trying to implement a single-line text view that will scroll automatically. But I unfortunatly cannot get it to work. The AutoScrollTextView is declared inside a LinearLayout (width and height = fill_parent). The class basically uses a Handler that calls itself to scroll by a given amount. I have simplified the code to only show a text view that should be scrolling by 5 pixels every second.

The log output is correct, the getScrollX() method returns the appropriate scrollX position.

If I don't call requestLayout(), nothing gets drawn. invalidate() has no effect.

Would anybody have a clue?

public class AutoScrollTextView extends TextView {

    public AutoScrollTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setSingleLine();
        setEllipsize(null);
        setText("Single-line text view that scrolls automatically if the text is too long to fit in the widget");
    }

    // begin to scroll the text from the original position
    public void startScrolling() {
        scrollHandler.sendEmptyMessage(0);
    }

    private Handler scrollHandler = new Handler() {
        private static final int REFRESH_INTERVAL = 1000;

        public void handleMessage(Message msg) {
            scrollBy(5, 0);
            requestLayout();
            Log.debug("Scrolled to " + getScrollX() + " px");
            sendEmptyMessageDelayed(0, REFRESH_INTERVAL);
        }
    };
}
Vincent Mimoun-Prat
  • 28,208
  • 16
  • 81
  • 124

9 Answers9

245

If you don't need to sub-class the TextView, you can try this in your layout file:

    <TextView
        android:text="Single-line text view that scrolls automatically if the text is too long to fit in the widget" 
        android:singleLine="true"
        android:ellipsize="marquee"
        android:marqueeRepeatLimit ="marquee_forever"
        android:focusable="true"
        android:focusableInTouchMode="true" 
        android:scrollHorizontally="true"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"/>

Also, in your code use the following:

findViewById(R.id.serviceColorCode).setSelected(true);

[Answer edited based on comments]

Angel Koh
  • 12,479
  • 7
  • 64
  • 91
Rajath
  • 11,787
  • 7
  • 48
  • 62
25

After these xml code as answered by @rajat

<TextView
        android:text="Single-line text view that scrolls automatically if the text is too long to fit in the widget" 
        android:singleLine="true" 
        android:ellipsize="marquee"
        android:marqueeRepeatLimit ="marquee_forever"
        android:focusable="true"
        android:focusableInTouchMode="true" 
        android:scrollHorizontally="true"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"/>

We need to set

TextView tv=(TextView)findViewById(R.id.textview1);
  tv.setSelected(true); 

which finally made mine work

CinCout
  • 9,486
  • 12
  • 49
  • 67
Sujeet Kumar Mehta
  • 2,761
  • 2
  • 20
  • 28
  • the whole text should be seen while scrolling through. the end text is dotted (too......) . so there is no point of scrolling. please suggest solution. – Sagar Nayak Aug 10 '16 at 05:02
  • I think you might have set android:ellipsize="end". Check once. Let me know if its not the case. Also if possible please share your code here – Sujeet Kumar Mehta Aug 10 '16 at 05:58
  • no i have "marquee" . but i am doing this inside an recyclerview. the outer recyclerview has a element that contains the textview. then the text view has a long text. i want to show it in one line . and this will scroll automatically for infinity. – Sagar Nayak Aug 10 '16 at 06:25
  • 1
    Ok. Not sure why using it is recycler view will disable the auto scroll. – Sujeet Kumar Mehta Aug 10 '16 at 09:43
18

My solution works:

<TextView
     android:id="@+id/titolotxt"
     android:layout_width="..."
     android:layout_height="..."
     android:ellipsize="marquee"
     android:gravity="left"
     android:marqueeRepeatLimit="marquee_forever"
     android:singleLine="true"
     android:text="@string/titolo"/>

And the TextView have to be setted selected: textView.setSelected(true); by code in onCreate for example.

Saurabh Bhandari
  • 2,438
  • 4
  • 26
  • 33
alfo888_ibg
  • 1,847
  • 5
  • 25
  • 43
3
// this TextView will marquee because it is selected
TextView marqueeText1 = (TextView) findViewById(R.id.marquee_text_1);
marqueeText1.setSelected(true);

<TextView
    android:id="@+id/marquee_text_1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."
    android:textSize="24sp"
    android:singleLine="true"
    android:ellipsize="marquee"
    android:marqueeRepeatLimit="marquee_forever"
    android:scrollHorizontally="true" />
Thamays
  • 2,978
  • 26
  • 31
3

Hint: Your Text should be big in length otherwise it won't work for small-length text if it does not exceed your screen size.

<  TextView
        android:id="@+id/support"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text=" enter the large text that wont fit on screen "
        android:singleLine="true"
        android:scrollHorizontally="true"
        android:ellipsize="marquee"
        android:marqueeRepeatLimit="marquee_forever"
        />

and in your activity

 TextView textView=findViewById(R.id.support);
        textView.setSelected(true);
3

In order to move text, besides adding attributes:

android:ellipsize="marquee"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:focusable="true"
android:clickable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true"

it is necessary for View to be in focus, so this can be done in two ways:

  1. Programmatically:

    tv.setSelected (true);
    
  2. Do everything in XML by adding requestFocus tag:

    <TextView 
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:ellipsize="marquee"
         android:singleLine="true"
         android:marqueeRepeatLimit="marquee_forever"
         android:focusable="true"
         android:clickable="true"
         android:focusableInTouchMode="true"
         android:scrollHorizontally="true">
         <requestFocus />
    </TextView>
    
  • Thanks. I wondered why all the solutions in the other answers didn't work by me. Because of the absence of the instruction `android:clickable="true"` – ka3ak Feb 24 '22 at 06:38
1

The only thing that worked for my case was using scrollview and setting the scroll programatically

Text View inside fragment

<HorizontalScrollView
        android:id="@+id/hsv_fragment_drafting_now_header_info"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="8dp"
        android:scrollbars="none">

        <TextView
               android:id="@+id/tv_fragment_drafting_now_header_info"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:fontFamily="@font/circular_std_book"
               android:maxLines="1"
               android:text="A very long text that will be reaching out the screen or view container"
               android:textSize="16sp" />

</HorizontalScrollView>

Animation, sliding_text.xml

<translate xmlns:android="http://schemas.android.com/apk/res/android"
      android:duration="8000"
      android:fromXDelta="100%"
      android:interpolator="@android:anim/linear_interpolator"
      android:repeatCount="infinite"
      android:repeatMode="restart"
      android:toXDelta="-100%" />

Block manual scroll and start animation

headerInfoScroll.setOnTouchListener(object : View.OnTouchListener{
    override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
         return true
    }
})

headerInfo.startAnimation(AnimationUtils.loadAnimation(this.context, R.anim.sliding_text))
0

Sometimes invalidate wont work until you call invalidate in main thread like follows:

handler.post(new Runnable() {

        @Override
        public void run() {
            yourView.invalidate();
        }
    });
Vitaliy A
  • 3,651
  • 1
  • 32
  • 34
0

setMovementMethod(new ScrollingMovementMethod()) with setHorizontallyScrolling(true) work in my case.

in .java:

tv = findViewById(R.id.textViewID);
tv.setMovementMethod(new ScrollingMovementMethod());
tv.setHorizontallyScrolling(true);
Alex IP
  • 21
  • 4