ChatGPT解决这个技术问题 Extra ChatGPT

Making TextView scrollable on Android

I am displaying text in a TextView that appears to be too long to fit into one screen. I need to make my TextView scrollable. How can I do that?

Here is the code:

final TextView tv = new TextView(this);
tv.setBackgroundResource(R.drawable.splash);
tv.setTypeface(face);
tv.setTextSize(18);
tv.setTextColor(R.color.BROWN);
tv.setGravity(Gravity.CENTER_VERTICAL| Gravity.CENTER_HORIZONTAL);
tv.setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View v, MotionEvent e) {
        Random r = new Random();
        int i = r.nextInt(101);
        if (e.getAction() == e.ACTION_DOWN) {
            tv.setText(tips[i]);
            tv.setBackgroundResource(R.drawable.inner);
        }
        return true;
    }
});
setContentView(tv);

A
Amit Chintawar

You don't need to use a ScrollView actually.

Just set the

android:scrollbars = "vertical"

properties of your TextView in your layout's xml file.

Then use:

yourTextView.setMovementMethod(new ScrollingMovementMethod());

in your code.

Bingo, it scrolls!


But surely maxLines requires you to enter an arbitrary number; this isn't something that will work for every screen size and font size? I find it simpler to just wrap it with a ScrollView, meaning I don't have to add any further XML attributes or code (like setting the movement method).
@Christopher, ScrollView requires 'android:layout_height' too.
@Regex: Well yes. Either you let the ScrollView take up as much space as it needs (e.g. via the android:fillViewport attribute), or you set the specific size you want. Using maxLines should not be used to set sizes of UI elements, so that is no solution.
you dont need to define maxlines. just the rest.
To clarify what everyone is saying about "smooth" scrolling: If you use this method scrolling is actually "smooth" (in that you can scroll pixel by pixel), however it is not kinetic. As soon as you remove your finger it stops scrolling instantly - there is no flicking. This is pretty unacceptable for a modern UI so I'm going to edit the answer to make sure other people don't waste time on this "solution".
P
Peter Mortensen

This is how I did it purely in XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <ScrollView
        android:id="@+id/SCROLLER_ID"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical"
        android:fillViewport="true">

        <TextView
            android:id="@+id/TEXT_STATUS_ID"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="1.0"/>
    </ScrollView>
</LinearLayout>

NOTES:

android:fillViewport="true" combined with android:layout_weight="1.0" will make the textview take up all available space. When defining the Scrollview, DO NOT specify android:layout_height="fill_parent" otherwise the scrollview doesn't work! (this has caused me to waste an hour just now! FFS).

PRO TIP:

To programmatically scroll to the bottom after appending text, use this:

mTextStatus = (TextView) findViewById(R.id.TEXT_STATUS_ID);
mScrollView = (ScrollView) findViewById(R.id.SCROLLER_ID);

private void scrollToBottom()
{
    mScrollView.post(new Runnable()
    {
        public void run()
        {
            mScrollView.smoothScrollTo(0, mTextStatus.getBottom());
        }
    });
}

There's no need to use mTextView.getBottom(), just use the method mScrollView.fullScroll(View.FOCUS_DOWN) as it is a part of the ScrollView API. See here and here for more info.
Android warns that either the LinearLayout or the ScrollView may be useless in this example (I removed the LinearLayout completely). It also warns that for the TextView, it should be android:layout_height="wrap_content" to match the ScrollView. These warnings may be due to the 3 years that have passed since this answer was posted. Regardless, this answer supports smooth scrolling and flicking...+1
Adding <!--suppress AndroidLintUselessParent --> above the ScrollView in the xml file will take care of those warnings.
The "pro tip" doesn't work for me, in Android API level 9. The textview stays scrolled to the top after appending text.
This approach is much better using the accepted answer approach will not produce a smooth user experience.
P
Peter Mortensen

All that is really necessary is the setMovementMethod(). Here's an example using a LinearLayout.

File main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView
    android:id="@+id/tv1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:text="@string/hello"
    />
</LinearLayout>

File WordExtractTest.java

public class WordExtractTest extends Activity {

    TextView tv1;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        tv1 = (TextView)findViewById(R.id.tv1);

        loadDoc();
    }

    private void loadDoc() {

        String s = "";

        for(int x=0; x<=100; x++) {
            s += "Line: " + String.valueOf(x) + "\n";
        }

        tv1.setMovementMethod(new ScrollingMovementMethod());

        tv1.setText(s);
    }
}

Is there any way to set this property in XML? I wonder why they would leave out that option.
It works but Is der any way to refresh it after scrolling? i mean after scrolling the TextView i am going to change text on it, but its position remains scrolled even if it is not required. its bcose previously i had applied scroll...
no scroll bars, and scrolling is clunky compared to the ScrollView method.
Use a StringBuilder instead of a String... what you have is a little wasteful.
this works but the scrolling is not smooth. Still works though thanks.
K
Keith Smiley

Make your textview just adding this

TextView textview= (TextView) findViewById(R.id.your_textview_id);
textview.setMovementMethod(new ScrollingMovementMethod());

This does not do kinetic scrolling. Do not use this.
@Timmmm how to get the kinetic scroll?
You don't want "kinetic scrolling" for a text that has to be read.
P
Peter Mortensen

It is not necessary to put in

android:Maxlines="AN_INTEGER"`

You can do your work by simply adding:

android:scrollbars = "vertical"

And, put this code in your Java class:

textview.setMovementMethod(new ScrollingMovementMethod());

Much better solution than the accepted one, as the scrollbar size exactly fits the text and you don't waste space.
when i am using ScrollView as parent, that time its not working
i wonder if the textview is vertically loong... just like the discussion here. But what if we want to focus (display) to the specific location of the text located at ...? is it available just like in html with ID #anchoring...? in android... textview is that possible? @AhsanRaza
P
Peter Mortensen

You can either

surround the TextView by a ScrollView; or set the Movement method to ScrollingMovementMethod.getInstance();.


P
Peter Mortensen

The best way I found:

Replace the TextView with an EditText with these extra attributes:

android:background="@null"
android:editable="false"
android:cursorVisible="false"

There is no need for wrapping in a ScrollView.


Easily the best and most appropriate answer, especially considering that EditText is a TextView subclass and the question is how to make the textview scrollable, not how to work around the problem. Would vote up twice if I could :)
@JustinBuser Couldn't disagree more. :) It's purely serendipitous that this works, and there's no guarantee it will in future versions of Android. If you want scrolling, use the scrolling tools that Android provides. ScrollView is the correct way to go.
@Madbreaks There is nothing "serendipitous" about it, EditText IS a TextView with a few added methods and overrides that is specifically tailored to accommodate varying length text. In particular EditText overrides the return value for the TextView getDefaultMovementMethod function. The default implementation returns NULL, EditText basically does the same thing all these other answers are suggesting. As far as using the tools that Android provides is concerned, the EditText class is far less likely to become deprecated than any of the other methods found in these answers.
@JustinBuser My problem with that though is you're depending on the default behavior of EditText, that is what I meant may very well change down the road (not at all that EditText would be deprecated). You can argue that, but again, the idea is to use components and features that are appropriate for the task at hand. ScrollView was explicitly designed to encompass scrolling. I always try to, and always suggest others use the right tool for the job. There are almost always multiple approaches to any given programming problem. Anyway, thanks for the thoughtful response.
9 years later still working, so I guess the scenarios in the comments didn't happen (yet)
M
MBH

Simple. This is how I did it:

XML Side: Java side: tv_log = (TextView) findViewById(R.id.tv_log); tv_log.setMovementMethod(new ScrollingMovementMethod());

Bonus:

To let the text view scroll down as the text fill it, you have to add:

    android:gravity="bottom"

to the TextView xml file. It will scroll down automatically as more text comes in.

Of course you need to add the text using the append function instead of set text:

    tv_log.append("\n" + text);

I used it for Log purpose.

I hope this helps ;)


P
Peter Mortensen

This is "How to apply ScrollBar to your TextView", using only XML.

First, you need to take a Textview control in the main.xml file and write some text into it ... like this:

<TextView
    android:id="@+id/TEXT"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:text="@string/long_text"/>

Next, place the text view control in between the scrollview to display the scroll bar for this text:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent">

    <ScrollView
        android:id="@+id/ScrollView01"
        android:layout_height="150px"
        android:layout_width="fill_parent">

        <TextView
            android:id="@+id/TEXT"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:text="@string/long_text"/>

    </ScrollView>
</RelativeLayout>

That's it...


Why even write this? This is an almost identical, albeit less correct, version of an answer that was posted over 6 months before you wrote it.
R
Raluca Lucaci

In kotlin for making the textview scrollable

myTextView.movementMethod= ScrollingMovementMethod()

and also add in xml this property

    android:scrollbars = "vertical"

I
IT-Dan

This will provide smooth scrolling text with a scroll bar.

ScrollView scroller = new ScrollView(this);
TextView tv = new TextView(this);
tv.setText(R.string.my_text);
scroller.addView(tv);

Enables blue animation. Best answer here IMO.
C
Community

The "pro tip" above from Someone Somewhere (Making TextView scrollable on Android) works great, however, what if you're dynamically adding text to the ScrollView and would like to automatically scroll to the bottom after an append only when the user is at the bottom of the ScrollView? (Perhaps because if the user has scrolled up to read something you don't want to automatically reset to the bottom during an append, which would be annoying.)

Anyway, here it is:

if ((mTextStatus.getMeasuredHeight() - mScrollView.getScrollY()) <=
        (mScrollView.getHeight() + mTextStatus.getLineHeight())) {
    scrollToBottom();
}

The mTextStatus.getLineHeight() will make it so that you don't scrollToBottom() if the user is within one line from the end of the ScrollView.


P
Peter Mortensen

If you want text to be scrolled within the textview, then you can follow the following:

First you should have to subclass textview.

And then use that.

Following is an example of a subclassed textview.

public class AutoScrollableTextView extends TextView {

    public AutoScrollableTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setEllipsize(TruncateAt.MARQUEE);
        setMarqueeRepeatLimit(-1);
        setSingleLine();
        setHorizontallyScrolling(true);
    }

    public AutoScrollableTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setEllipsize(TruncateAt.MARQUEE);
        setMarqueeRepeatLimit(-1);
        setSingleLine();
        setHorizontallyScrolling(true);
    }

    public AutoScrollableTextView(Context context) {
        super(context);
        setEllipsize(TruncateAt.MARQUEE);
        setMarqueeRepeatLimit(-1);
        setSingleLine();
        setHorizontallyScrolling(true);
    }

    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        if(focused)
            super.onFocusChanged(focused, direction, previouslyFocusedRect);
    }

    @Override
    public void onWindowFocusChanged(boolean focused) {
        if(focused)
            super.onWindowFocusChanged(focused);
    }

    @Override
    public boolean isFocused() {
        return true;
    }
}

Now, you have to use that in the XML in this way:

 <com.yourpackagename.AutoScrollableTextView
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:text="This is very very long text to be scrolled"
 />

That's it.


P
Peter Mortensen

Add the following in the textview in XML.

android:scrollbars="vertical"

And finally, add

textView.setMovementMethod(new ScrollingMovementMethod());

in the Java file.


This does not do kinetic scrolling. Do not use it.
M
Mori

If you use Kotlin , in this way : XML

 <TextView
            android:id="@+id/tvMore"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:maxLines="3"
            android:scrollbars="vertical" />

Activity

tvMore.movementMethod = ScrollingMovementMethod()

a
android.weasel

I didn't find TextView scrolling to support the 'fling' gesture, where it continues scrolling after a flick up or down. I ended up implementing that myself because I didn't want to use a ScrollView for various reasons, and there didn't seem to be a MovementMethod that both allowed me to select text and click on links.


soo... how did you add the fling gesture?
P
Peter Mortensen

When you are done with scrollable, add this line to the view's last line when you enter anything in the view:

((ScrollView) findViewById(R.id.TableScroller)).fullScroll(View.FOCUS_DOWN);

dude,tablescroller is a view that was identified by the id attribute from the XML that was processed in .. u just try it.. it ll work fine.. its works fr me..
J
Justin Buser

If you don't want to use the EditText solution then you might have better luck with:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.yourLayout);
    (TextView)findViewById(R.id.yourTextViewId).setMovementMethod(ArrowKeyMovementMethod.getInstance());
}

P
Peter Mortensen

Add this to your XML layout:

android:ellipsize="marquee"
android:focusable="false"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:text="To Make An textView Scrollable Inside The TextView Using Marquee"

And in code you have to write the following lines:

textview.setSelected(true);
textView.setMovementMethod(new ScrollingMovementMethod());

This does not do kinetic scrolling. Do not use it.
i dont want to ellipsize the end text. how do i do it.
@SagarNayak use android:ellipsize="none"
s
slfan
yourtextView.setMovementMethod(new ScrollingMovementMethod());

you can scroll it now.


This is what the accepted answer already says. From Review.
F
FoxDonut

I know this is an older post, but this is how I am handling the issue on the Java side.

    // Allow textView to scroll
    tv.setSingleLine(true);
    tv.setHorizontallyScrolling(true);
    tv.setEllipsize(TextUtils.TruncateAt.MARQUEE);
    tv.setMarqueeRepeatLimit(-1); // Infinite
    // TextView must be 'selected'
    tv.setSelected(true);
    // Padding not necessary, but this helps so the text isn't right
    // up against the side of a screen/layout
    tv.setPadding(10, 0, 10, 0);

w
whitepearl

The code below creates an automatic horizontal scrolling textview:

While adding TextView to xml use

<TextView android:maxLines="1" 
          android:ellipsize="marquee"
          android:scrollHorizontally="true"/>

Set the following properties of TextView in onCreate()

tv.setSelected(true);
tv.setHorizontallyScrolling(true); 

R
Rohit Mandiwal

I had this problem when I was using TextView inside the ScrollView. This solution has worked for me.

scrollView.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                description.getParent().requestDisallowInterceptTouchEvent(false);

                return false;
            }
        });

        description.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                description.getParent().requestDisallowInterceptTouchEvent(true);

                return false;
            }
        });

L
Linh

Use it like this

<TextView  
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:maxLines = "AN_INTEGER"
    android:scrollbars = "vertical"
/>

AN_INTEGER' is incompatible with attribute maxLines (attr) integer min=0.
what is AN_INTEGER?
K
Khemraj Sharma

Put maxLines and scrollbars inside TextView in xml.

<TextView android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:scrollbars="vertical"
    android:maxLines="5" // any number of max line here.
    />

Then in java code.

textView.setMovementMethod(new ScrollingMovementMethod());


P
Prince Dholakiya

whenever you need to use the ScrollView as parent, And you also use the scroll movement method with TextView.

And When you portrait to landscape your device that time occur some issue. (like) entire page is scrollable but scroll movement method can't work.

if you still need to use ScrollView as parent or scroll movement method then you also use below desc.

If you do not have any problems then you use EditText instead of TextView

see below :

<EditText
     android:id="@+id/description_text_question"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:background="@null"
     android:editable="false"
     android:cursorVisible="false"
     android:maxLines="6"/>

Here, the EditText behaves like TextView

And your issue will be resolved


r
rll

In my case.Constraint Layout.AS 2.3.

Code implementation:

YOUR_TEXTVIEW.setMovementMethod(new ScrollingMovementMethod());

XML:

android:scrollbars="vertical"
android:scrollIndicators="right|end"

P
Peter Mortensen

I struggled with this for over a week and finally figured out how to make this work!

My issue was that everything would scroll as a 'block'. The text itself was scrolling, but as a chunk rather than line by line. This obviously didn't work for me, because it would cut off lines at the bottom. All of the previous solutions did not work for me, so I crafted my own.

Here is the easiest solution by far:

Make a class file called: 'PerfectScrollableTextView' inside a package, then copy and paste this code in:

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.TextView;

public class PerfectScrollableTextView extends TextView {

    public PerfectScrollableTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setVerticalScrollBarEnabled(true);
        setHorizontallyScrolling(false);
    }

    public PerfectScrollableTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setVerticalScrollBarEnabled(true);
        setHorizontallyScrolling(false);
    }

    public PerfectScrollableTextView(Context context) {
        super(context);
        setVerticalScrollBarEnabled(true);
        setHorizontallyScrolling(false);
    }

    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        if(focused)
            super.onFocusChanged(focused, direction, previouslyFocusedRect);
    }

    @Override
    public void onWindowFocusChanged(boolean focused) {
        if(focused)
            super.onWindowFocusChanged(focused);
    }

    @Override
    public boolean isFocused() {
        return true;
    }
}

Finally change your 'TextView' in XML:

From: <TextView

To: <com.your_app_goes_here.PerfectScrollableTextView


100% Perfect answer. I faced the same issue as you mention in the description. apply many solutions but not work perfectly. but your solution working perfectly in every case. save my time man :) Thanks
Doesn't work at all for me. No scrolling at all. The only problem the other solutions have is the missing kinetic scrolling. Can't see how your solution fixed that.
@Lothar I'm not sure, this was 7 years ago so I'm sure a lot has changed, sorry about that!
h
hash

XML - You can use android:scrollHorizontally Attribute

Whether the text is allowed to be wider than the view (and therefore can be scrolled horizontally).

May be a boolean value, such as "true" or "false".

Prigramacaly - setHorizontallyScrolling(boolean)


m
mohamad sheikhi

Try this:

android:scrollbars = "vertical"