How can I make a TextView automatically scroll as

2019-02-01 18:51发布

问题:

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

回答1:

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



回答2:

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.



回答3:

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() .



回答4:

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)



回答5:

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());


回答6:

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.



回答7:

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);


回答8:

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.