Umożliwianie przewijania TextView na Androidzie


771

Wyświetlam tekst w widoku tekstowym, który wydaje się zbyt długi, aby zmieścił się na jednym ekranie. Muszę umożliwić przewijanie TextView. Jak mogę to zrobić?

Oto kod:

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

Odpowiedzi:


1719

Nie musisz używać ScrollView właściwie .

Po prostu ustaw

android:scrollbars = "vertical"

właściwości twojego TextView pliku xml twojego układu.

Następnie użyj:

yourTextView.setMovementMethod(new ScrollingMovementMethod());

w twoim kodzie.

Bingo, przewija się!


96
Ale z pewnością maxLineswymaga podania dowolnej liczby; to nie jest coś, co będzie działać dla każdego rozmiaru ekranu i rozmiaru czcionki? Uważam, że łatwiej jest po prostu owinąć go ScrollView, co oznacza, że ​​nie muszę dodawać żadnych dalszych atrybutów XML ani kodu (np. Ustawiania metody przenoszenia).
Christopher Orr,

12
@Christopher, ScrollView wymaga również „android: layout_height”.
Regex Świeżak

11
@Regex: Cóż, tak. Albo pozwalasz ScrollViewzająć tyle miejsca, ile potrzebuje (np. Za pomocą android:fillViewportatrybutu), lub ustaw odpowiedni rozmiar. Używanie maxLinesnie powinno być używane do ustawiania rozmiarów elementów interfejsu użytkownika, więc to nie jest rozwiązanie.
Christopher Orr,

62
nie musisz definiować maksymalnych linii. tylko reszta.
Stevanicus

13
Aby wyjaśnić, co wszyscy mówią o „płynnym” przewijaniu: jeśli używasz tej metody, przewijanie jest w rzeczywistości „płynne” (tzn. Możesz przewijać piksel po pikselu), jednak nie jest ono kinetyczne. Gdy tylko zdejmiesz palec, natychmiast przestaje on przewijać - nie trzepocze. Jest to nie do przyjęcia w przypadku nowoczesnego interfejsu użytkownika, dlatego zmienię odpowiedź, aby upewnić się, że inni ludzie nie będą tracić czasu na to „rozwiązanie”.
Timmmm,

310

Oto jak to zrobiłem wyłącznie w języku 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>

UWAGI:

  1. android:fillViewport="true"w połączeniu z android:layout_weight="1.0"spowoduje, że widok tekstu zajmie całą dostępną przestrzeń.

  2. Podczas definiowania widoku przewijania NIE określaj android:layout_height="fill_parent"inaczej, widok przewijania nie działa! (to spowodowało, że zmarnowałem godzinę teraz! FFS).

WSKAZÓWKA PRO:

Aby programowo przewinąć do dołu po dołączeniu tekstu, użyj tego:

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

12
Nie ma potrzeby używania mTextView.getBottom(), wystarczy użyć metody, mScrollView.fullScroll(View.FOCUS_DOWN)ponieważ jest ona częścią interfejsu ScrollView API. Zobacz tutaj i tutaj, aby uzyskać więcej informacji.
ChuongPham,

7
Android ostrzega, że ​​albo LinearLayoutlub ScrollViewmogą być bezużyteczne w tym przykładzie ( LinearLayoutcałkowicie usunąłem ). Ostrzega również, że w przypadku TextView, powinno być android:layout_height="wrap_content"dopasowanie do ScrollView. Te ostrzeżenia mogą wynikać z 3 lat, które upłynęły od opublikowania tej odpowiedzi. Niezależnie od tego, ta odpowiedź obsługuje płynne przewijanie i przesuwanie ... + 1
skia.heliou

Dodanie <!--suppress AndroidLintUselessParent -->powyżej ScrollVieww pliku xml zajmie się tymi ostrzeżeniami.
Louie Bertoncin,

„Profesjonalna wskazówka” nie działa dla mnie na 9. poziomie interfejsu API Androida. Widok tekstu pozostaje przewijany do góry po dodaniu tekstu.
LarsH 21.04.16

Podejście to jest znacznie lepsze przy użyciu metody przyjętej odpowiedzi nie zapewni płynnego działania użytkownika.
seyedrezafar

120

Wszystko, co jest naprawdę konieczne, to setMovementMethod (). Oto przykład z wykorzystaniem LinearLayout.

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

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

3
Czy jest jakiś sposób na ustawienie tej właściwości w XML? Zastanawiam się, dlaczego mieliby pominąć tę opcję.
Thalur,

Działa, ale czy można go odświeżyć po przewinięciu? mam na myśli, że po przewinięciu TextView zamierzam na nim zmienić tekst, ale jego pozycja pozostaje przewijana, nawet jeśli nie jest wymagana. jego poprzednio zastosowałem zwój ...
Nirav Dangi

9
brak pasków przewijania, a przewijanie jest niewygodne w porównaniu do ScrollViewmetody.
Jeffrey Blattman

1
Użyj StringBuilderzamiast String... to, co masz, jest trochę marnotrawstwem.
Alex Lockwood,

4
to działa, ale przewijanie nie jest płynne. Nadal działa dzięki.
frostymarvellous


41

Nie trzeba go wkładać

android:Maxlines="AN_INTEGER"`

Możesz wykonać swoją pracę, po prostu dodając:

android:scrollbars = "vertical"

I umieść ten kod w swojej klasie Java:

textview.setMovementMethod(new ScrollingMovementMethod());

O wiele lepsze rozwiązanie niż przyjęte, ponieważ rozmiar paska przewijania dokładnie pasuje do tekstu i nie marnujesz miejsca.
FractalBob,

kiedy używam ScrollView jako rodzica, tym razem nie działa
Prince

27

Możesz albo

  1. otaczają TextViewprzez ScrollView; lub
  2. ustaw metodę ruchu na ScrollingMovementMethod.getInstance();.

22

Najlepszy sposób, jaki znalazłem:

Zamień TextView na EditText z następującymi dodatkowymi atrybutami:

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

Nie ma potrzeby owijania w ScrollView.


2
Łatwo najlepsza i najbardziej odpowiednia odpowiedź, szczególnie biorąc pod uwagę, że EditText jest podklasą TextView, a pytanie dotyczy tego, jak sprawić, by przeglądanie tekstu było przewijalne, a nie jak obejść problem. Zagłosowałbym dwa razy, gdybym mógł :)
Justin Buser

4
@JustinBuser Nie można się nie zgodzić. :) Działa to dość czysto, i nie ma gwarancji, że będzie działać w przyszłych wersjach Androida. Jeśli chcesz przewijać, skorzystaj z narzędzi przewijania dostępnych w systemie Android. ScrollViewjest właściwą drogą.
Madbreaks

1
@Madbreaks Nie ma w tym nic „przypadkowego”, EditText JEST TextView z kilkoma dodanymi metodami i przesłonięciami, które są specjalnie dostosowane do obsługi tekstu o różnej długości. W szczególności EditText przesłania wartość zwracaną dla funkcji getDefaultMovementMethod TextView. Domyślna implementacja zwraca NULL, EditText zasadniczo robi to samo, co sugerują wszystkie inne odpowiedzi. Jeśli chodzi o korzystanie z narzędzi udostępnianych przez system Android, klasa EditText ma znacznie mniejsze szanse na wycofanie się niż jakakolwiek inna metoda znaleziona w tych odpowiedziach.
Justin Buser

4
@JustinBuser Mój problem z tym jest jednak jesteś w zależności od domyślnego zachowania EditText, że to mi chodziło może równie dobrze zmienić w dół drogi (nie w ogóle, że EditText będzie przestarzałe). Można argumentować, ale znowu chodzi o to, aby użyć komponentów i funkcji odpowiednich do danego zadania. ScrollView został wyraźnie zaprojektowany tak, aby obejmował przewijanie. Zawsze staram się i zawsze sugeruję, aby inni używali odpowiedniego narzędzia do pracy. Prawie zawsze istnieje wiele podejść do dowolnego problemu programistycznego. W każdym razie dzięki za przemyślaną odpowiedź.
Madbreaks

16

Prosty. Oto jak to zrobiłem:

  1. Strona XML:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        tools:context="com.mbh.usbcom.MainActivity">
        <TextView
            android:id="@+id/tv_log"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="vertical"
            android:text="Log:" />
    </RelativeLayout>
  2. Strona Java:

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

Premia:

Aby widok tekstu przewijał się w dół, gdy wypełnia go tekst, musisz dodać:

    android:gravity="bottom"

do pliku XML TextView. Przewinie się automatycznie w dół, gdy pojawi się więcej tekstu.

Oczywiście musisz dodać tekst za pomocą funkcji append zamiast ustawiać tekst:

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

Użyłem go do celów dziennika.

Mam nadzieję, że to pomoże ;)


14

To jest „Jak zastosować ScrollBar do TextView”, używając tylko XML.

Najpierw musisz przejąć kontrolę Textview w pliku main.xml i napisać w nim trochę tekstu ... w ten sposób:

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

Następnie umieść kontrolkę widoku tekstu pomiędzy widokiem przewijania, aby wyświetlić pasek przewijania tego tekstu:

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

Otóż ​​to...


6
Po co w ogóle to pisać? Jest to prawie identyczna, choć mniej poprawna wersja odpowiedzi, która została opublikowana ponad 6 miesięcy przed napisaniem.
Justin Buser

11

Zapewni to płynne przewijanie tekstu z paskiem przewijania.

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

Włącza niebieską animację. Najlepsza odpowiedź tutaj IMO.
Griffin W.,

11

Powyższa „profesjonalna wskazówka” z Someone Somewhere ( zmienianie przewijania TextView na Androida ) działa jednak świetnie, co jeśli dynamicznie dodajesz tekst do ScrollView i chciałbyś automatycznie przewijać do dołu po dołączeniu tylko wtedy, gdy użytkownik jest w spód ScrollView? (Być może dlatego, że jeśli użytkownik przewinął w górę, aby przeczytać coś, czego nie chcesz automatycznie resetować do dołu podczas dołączania, co byłoby denerwujące).

W każdym razie tutaj jest:

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

Funkcja mTextStatus.getLineHeight () sprawi, że nie będziesz przewijaćToBottom (), jeśli użytkownik znajduje się w obrębie jednej linii od końca ScrollView.


10

Jeśli chcesz przewinąć tekst w widoku tekstu, możesz wykonać następujące czynności:

Najpierw należy podklasę podglądu tekstu.

A potem użyj tego.

Poniżej znajduje się przykład widoku tekstu z podklasą.

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

Teraz musisz użyć tego w XML w następujący sposób:

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

Otóż ​​to.


7

Dodaj następujące w widoku tekstu w XML.

android:scrollbars="vertical"

I na koniec dodaj

textView.setMovementMethod(new ScrollingMovementMethod());

w pliku Java.


1
Nie powoduje to przewijania kinetycznego. Nie używaj tego.
Timmmm,

6

Nie znalazłem przewijania TextView do obsługi gestu „fling”, w którym przewija się on po przesunięciu w górę lub w dół. Skończyło się na tym, że sam to wdrożyłem, ponieważ nie chciałem używać ScrollView z różnych powodów, i nie było żadnej metody MovementMethod, która pozwalała mi wybierać tekst i klikać linki.


6
soo ... jak dodałeś gest rzutu?
Lou Morda,

6

W kotlin za przewijanie widoku tekstu

myTextView.movementMethod= ScrollingMovementMethod()

a także dodać w xml tę właściwość

    android:scrollbars = "vertical"

5

Gdy skończysz przewijanie, dodaj tę linię do ostatniej linii widoku, gdy wprowadzisz cokolwiek w widoku:

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

koleś, tablecroller to widok, który został zidentyfikowany przez atrybut id z XML-a, który został przetworzony ... po prostu spróbuj ... będzie działał dobrze .. działa ode mnie ..
Rahul Baradia

4

Jeśli nie chcesz używać rozwiązania EditText, możesz mieć więcej szczęścia z:

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

4

Dodaj to do swojego układu XML:

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"

W kodzie musisz wpisać następujące wiersze:

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

2
Nie powoduje to przewijania kinetycznego. Nie używaj tego.
Timmmm,

nie chcę powiększać tekstu końcowego. jak mam to zrobić.
Sagar Nayak,

@SagarNayak używa Androida: ellipsize = "none"
Francis

2

Poniższy kod tworzy automatyczne przewijanie tekstu w poziomie:

Podczas dodawania TextView do xml użyj

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

Ustaw następujące właściwości TextView w funkcji onCreate ()

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


1

Użyj tego w ten sposób

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

0

W moim przypadku Ograniczenie układu. AS 2.3.

Implementacja kodu:

YOUR_TEXTVIEW.setMovementMethod(new ScrollingMovementMethod());

XML:

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

0

Walczyłem z tym przez ponad tydzień i w końcu wymyśliłem, jak to zrobić!

Mój problem polegał na tym, że wszystko przewijało się jako „blok”. Sam tekst przewijał się, ale jako fragment, a nie linia po linii. To oczywiście nie działało dla mnie, ponieważ odcinałoby linie na dole. Wszystkie poprzednie rozwiązania nie działały dla mnie, więc stworzyłem własne.

Oto najprostsze jak dotąd rozwiązanie:

Utwórz plik klasy o nazwie: „PerfectScrollableTextView” w pakiecie, a następnie skopiuj i wklej ten kod w:

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

Na koniec zmień swój „TextView” w XML:

Od: <TextView

Do: <com.your_app_goes_here.PerfectScrollableTextView


1
100% idealna odpowiedź. Napotkałem ten sam problem, o którym wspomniałeś w opisie. zastosuj wiele rozwiązań, ale nie działają idealnie. ale Twoje rozwiązanie działa idealnie w każdym przypadku. oszczędź mój czas, człowieku :) Dzięki
Daxesh Vekariya

@DaxeshVekariya Cieszę się, że to zadziałało!
Petro

0

Put maxLinesa scrollbarswewnątrz TextView w xml.

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

Następnie w kodzie Java.

textView.setMovementMethod(new ScrollingMovementMethod());


0

Miałem ten problem, gdy korzystałem z TextViewwewnątrz ScrollView. To rozwiązanie zadziałało dla mnie.

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

0

ilekroć potrzebujesz użyć ScrollView jako elementu nadrzędnego , a także używasz metody przewijania w TextView.

A kiedy portretujesz, aby ustawić urządzenie w orientacji poziomej, czas pojawia się jakiś problem . (jak) cała strona jest przewijalna, ale metoda przewijania nie działa.

jeśli nadal musisz używać ScrollView jako metody nadrzędnej lub przewijania, użyj również poniższego opisu.

Jeśli nie masz żadnych problemów, użyj EditText zamiast TextView

patrz poniżej:

<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"/>

Tutaj EditText zachowuje się jak TextView

Twój problem zostanie rozwiązany


0

XML - możesz użyć android:scrollHorizontallyatrybutu

Określa, czy tekst może być szerszy niż widok (i dlatego może być przewijany w poziomie).

Może być wartością logiczną, taką jak „prawda” lub „fałsz”.

Prigramacaly - setHorizontallyScrolling(boolean)


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.