38

So, I have a TextView like so:

<TextView android:layout_width="fill_parent" android:layout_height="140.7dp" android:id="@+id/terminalOutput" android:layout_marginBottom="0.0dp" android:scrollbars="vertical" android:scrollbarAlwaysDrawVerticalTrack="true" android:maxLines="8" /> 

I use it as a sort of running log, displayed to the user so they can monitor progress of a task that takes about 3 minutes. However, once I go over 8 lines, the text goes off screen. This is unintuitive to the user because they have no way of knowing that it went off screen, other than to manually poll by trying scroll down.

How can I make it so that every time I add some text to this TextView I make it scroll down as low as it can go?

Also, this is in Xamarin Android, but I don't think it's relevant. It's easy to translate between it and Java

5
  • 2
    I'm not sure, but try adding android:gravity="bottom"? Commented Nov 7, 2013 at 2:12
  • change this : android:layout_marginBottom="10dp" and set gravity to bottom Commented Nov 7, 2013 at 2:18
  • Well, you do have android:maxLines="8" as a line in your TextView. Commented Nov 7, 2013 at 2:28
  • @antimo setting gravity to bottom seems to work good enough for me Commented Nov 7, 2013 at 2:31
  • 1
    @AndrewT. : gravity made the trick, why don't you put it as an answer. Thanks anyway. Commented Feb 2, 2017 at 11:18

9 Answers 9

78

From your Code, two steps have to do:

Step 1

Although you code in Xamarin Android, but as in Java in the xxxActivity.java for terminalOutput invoke must be like this

TextView outputText = (TextView) findViewById(R.id.terminalOutput); outputText.setMovementMethod(new ScrollingMovementMethod()); 

Method setMovementMethod() by parameter ScrollingMovementMethod() is the gimmick.

Step 2

And in the layout as in Java-Android also in activity_xxx.xml for the TextView Declaration as above must have to add this

android:gravity="bottom" 

When you add new line into the outputText like this:

outputText.append("\n"+"New text line."); 

It will scroll to the last line automatically, and these all the magic for your need.

Sign up to request clarification or add additional context in comments.

3 Comments

ScrollingMovementMethod() is a real gimmick, however is scrolls text without these Android "terminators" in top or bottom.
Thank you this helped me alot!! i also have my layout_height set to android:layout_height="wrap_content"
This works, but after phone rotate from portrait to horizontal, the textview content is hidden.
34

As per answer here Making TextView Scrollable in Android

You don't need to use a ScrollView actually.

Just set the

android:maxLines = "AN_INTEGER"

android:scrollbars = "vertical" properties of your TextView in your layout's xml file.

Then use:

yourTextView.setMovementMethod(new ScrollingMovementMethod());

in your code.

That will work..

3 Comments

I know the other answer is probably more general purpose and useful across more situations, but this answer was extremely simple and worked good enough for me
This answer is not correct, the question refers to "automatically scroll". The answer is bellow, using gravity.
Be careful to have a non-zero height for the TextView. If you set layout_height to 0dp as Android studio suggests for performance, auto-scroll will not work
10

None of these answers were quite what I wanted, so I came up with this.

textView.append(log); while (textView.canScrollVertically(1)) { textView.scrollBy(0, 10); } 

Do not forget to set movement method before scrolling

textView.setMovementMethod(new ScrollingMovementMethod()); 

2 Comments

if you can control where the text is appended, like in your example, you can simply follow textView.append(log) with textView.bringPointIntoView(textView.length()).
@AlexCohn this is exactly what I was looking for. Text starts at the top and then scrolls down as it is appended to the bottom and would otherwise go off screen.
9

Had the same question. Tried several decisions from this and similar discussions, nothing worked. Solved it this way:

edtConsoleText.setSelection(edtConsoleText.getText().length()); 

after every .append() .

Comments

5

You can try in 2 solutions:

  1. Put TextView in a ScrollView

    <ScrollView android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Your Text" > </TextView> </ScrollView> 
  2. Use custom scroll TextView (same as traditional TextView but it can scroll)

    import android.content.Context; import android.graphics.Rect; import android.text.TextPaint; import android.util.AttributeSet; import android.view.animation.LinearInterpolator; import android.widget.Scroller; import android.widget.TextView; public class ScrollTextView extends TextView { // scrolling feature private Scroller mSlr; // milliseconds for a round of scrolling private int mRndDuration = 250; // the X offset when paused private int mXPaused = 0; // whether it's being paused private boolean mPaused = true; /* * constructor */ public ScrollTextView(Context context) { this(context, null); // customize the TextView setSingleLine(); setEllipsize(null); setVisibility(INVISIBLE); } /* * constructor */ public ScrollTextView(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.textViewStyle); // customize the TextView setSingleLine(); setEllipsize(null); setVisibility(INVISIBLE); } /* * constructor */ public ScrollTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // customize the TextView setSingleLine(); setEllipsize(null); setVisibility(INVISIBLE); } /** * begin to scroll the text from the original position */ public void startScroll() { // begin from the very right side mXPaused = -1 * getWidth(); // assume it's paused mPaused = true; resumeScroll(); } /** * resume the scroll from the pausing point */ public void resumeScroll() { if (!mPaused) return; // Do not know why it would not scroll sometimes // if setHorizontallyScrolling is called in constructor. setHorizontallyScrolling(true); // use LinearInterpolator for steady scrolling mSlr = new Scroller(this.getContext(), new LinearInterpolator()); setScroller(mSlr); int scrollingLen = calculateScrollingLen(); int distance = scrollingLen - (getWidth() + mXPaused); int duration = (new Double(mRndDuration * distance * 1.00000 / scrollingLen)).intValue(); setVisibility(VISIBLE); mSlr.startScroll(mXPaused, 0, distance, 0, duration); mPaused = false; } /** * calculate the scrolling length of the text in pixel * * @return the scrolling length in pixels */ private int calculateScrollingLen() { TextPaint tp = getPaint(); Rect rect = new Rect(); String strTxt = getText().toString(); tp.getTextBounds(strTxt, 0, strTxt.length(), rect); int scrollingLen = rect.width() + getWidth(); rect = null; return scrollingLen; } /** * pause scrolling the text */ public void pauseScroll() { if (null == mSlr) return; if (mPaused) return; mPaused = true; // abortAnimation sets the current X to be the final X, // and sets isFinished to be true // so current position shall be saved mXPaused = mSlr.getCurrX(); mSlr.abortAnimation(); } @Override /* * override the computeScroll to restart scrolling when finished so as that * the text is scrolled forever */ public void computeScroll() { super.computeScroll(); if (null == mSlr) return; if (mSlr.isFinished() && (!mPaused)) { this.startScroll(); } } public int getRndDuration() { return mRndDuration; } public void setRndDuration(int duration) { this.mRndDuration = duration; } public boolean isPaused() { return mPaused; } } 

How to use:

ScrollTextView scrolltext = (ScrollTextView) findViewById(R.id.YourTextView); 

(ScrollTextView class source: http://bear-polka.blogspot.com/2009/01/scrolltextview-scrolling-textview-for.html)

Comments

4

From "How to scroll to bottom in a ScrollView on activity startup":

final ScrollView scrollview = ((ScrollView) findViewById(R.id.scrollview)); scrollview.post(new Runnable() { @Override public void run() { scrollview.fullScroll(ScrollView.FOCUS_DOWN); } }); 

What you need is to put fullScroll() after append operation.

Comments

2

I am using Xmarin.

My solution is as many people mentioned, to textView inside a ScrollView.

If you want to see the new line at the bottom of the view, use

android:layout_gravity="bottom" 

This keeps the new line at the bottom until you scroll the view. The view stays wherever you have scrolled.

No code is needed.

However, if you want the contents is always at bottom after appending, you need to add code after append():

myText.Append(...); myscroll.FullScroll(FocusSearchDirection.Down); 

Comments

0

For me nothing worked perfectly except a combination of these two :-

  • Setting scroller.scrollTo(0, 70); in your java class.Use it before setting your textview but after appending that String. 52 dp is the height of my device.You can find it out using scroller.getBottom()); So I used 70 to adjust for the scroll view.
  • Setting android:scrollY="30dp" in your textview.

Comments

0

In my case, nothing worked at first because I was apparently attempting to make changes to the UI (auto scrolling up after adding text that is out of view), outside of the UI thread. The words would display but with no auto scroll. Correction, setText would work but not append.

My call for auto scroll was not in a UI thread because I coded the call to be made in response to a socket onMessage call; which I run on its own thread. So, I had to enclose my function call with the following code and everything worked.

 runOnUiThread(new Runnable() { @Override public void run() { // Stuff that updates the UI } }); 

I'm sure all of the methods would work in someway so long as you are running it on a UI thread. But, to achieve the autoscroll effect for a "chat room" i.e. new text at top of chat window but when amount of text is longer than the window - autoscroll up the new messages into view, i just used the ... fullScroll(View.FOCUS_DOWN) ... method.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.