Czy mogę programowo przewijać ScrollView w systemie Android?

145

Czy istnieje sposób na ScrollViewprogramowe przewijanie do określonej pozycji?

Stworzyłem dynamikę, TableLayoutktóra jest umieszczona w ScrollView. Dlatego chcę, aby w przypadku określonej akcji (takiej jak kliknięcie przycisku itp.) Określony wiersz powinien automatycznie przewijać się na najwyższą pozycję.

Czy to możliwe?

Arun Badole
źródło

Odpowiedzi:

165
ScrollView sv = (ScrollView)findViewById(R.id.scrl);
sv.scrollTo(0, sv.getBottom());

lub

sv.scrollTo(5, 10);

Android
źródło
43
Łącząc odpowiedź ercu i komentarz na jej temat, najlepszym sposobem wydaje się być:mScrollView.post(new Runnable() { public void run() { mScrollView.fullScroll(View.FOCUS_DOWN); } });
sparrowt
2
scrollTo () nie zwróci pożądania. Należy przejść z fullScroll ()
Amit Yadav
3
Bardziej ładny zwój ma naturalny efekt: sv.smoothScrollTo (5, 10)
ivan.panasiuk
205

Odpowiedź od Pragna nie zawsze działa, spróbuj tego:

mScrollView.post(new Runnable() { 
        public void run() { 
             mScrollView.scrollTo(0, mScrollView.getBottom());
        } 
});

lub

mScrollView.post(new Runnable() { 
        public void run() { 
             mScrollView.fullScroll(mScrollView.FOCUS_DOWN);
        } 
});

jeśli chcesz przewinąć do początku

mScrollView.post(new Runnable() { 
        public void run() { 
             mScrollView.fullScroll(mScrollView.FOCUS_UP);
        } 
});
ercu
źródło
28
Użyłem mScrollView.fullScroll(mScrollView.FOCUS_DOWN);z powodzeniem.
amcc,
3
Mogę potwierdzić ustalenia Vanthela. mScrollView.fullScroll w postu, który można uruchomić, załatwił sprawę.
AlanKley
1
Doskonały ! Rzeczywiście, bez Runnable to nie zadziałało. Teraz działa ! :)
Regis_AG
5
@HiteshDhamshaniya Jeśli chcesz płynnego przewijania, spróbuj mScrollView.smoothScrollTo(0, mScrollView.getBottom());.
Mike Ortiz
1
Dlaczego potrzebuje posttutaj?
Liuting
35

Chciałem, aby scrollView przewijał się bezpośrednio po onCreateView () (nie po np. Kliknięciu przycisku). Aby to działało, potrzebowałem ViewTreeObserver:

mScrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mScrollView.post(new Runnable() {
                public void run() {
                    mScrollView.fullScroll(View.FOCUS_DOWN);
                }
            });
        }
    });

Ale pamiętaj, że będzie to wywoływane za każdym razem, gdy coś zostanie ułożone (np. Jeśli ustawisz widok jako niewidoczny lub podobny), więc nie zapomnij usunąć tego nasłuchiwania, jeśli już go nie potrzebujesz:

public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) na SDK Lvl <16

lub

public void removeOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) w SDK Lvl> = 16

Patrick Favre
źródło
23

Jest tu wiele dobrych odpowiedzi, ale chcę dodać tylko jedną rzecz. Czasami zdarza się, że chcesz przewinąć ScrollView do określonego widoku układu, zamiast pełnego przewijania do góry lub do dołu.

Prosty przykład: w formularzu rejestracyjnym, jeśli użytkownik dotknie przycisku „Zarejestruj się”, gdy tekst edycji formularza nie jest wypełniony, chcesz przewinąć do tego konkretnego tekstu edycji, aby poinformować użytkownika, że ​​musi wypełnić to pole.

W takim przypadku możesz zrobić coś takiego:

scrollView.post(new Runnable() { 
        public void run() { 
             scrollView.scrollTo(0, editText.getBottom());
        } 
});

lub, jeśli chcesz płynne przewijanie zamiast natychmiastowego przewijania:

scrollView.post(new Runnable() { 
            public void run() { 
                 scrollView.smoothScrollTo(0, editText.getBottom());
            } 
    });

Oczywiście zamiast opcji Edytuj tekst można użyć dowolnego typu widoku. Zwróć uwagę, że getBottom () zwraca współrzędne widoku na podstawie jego układu nadrzędnego, więc wszystkie widoki używane wewnątrz ScrollView powinny mieć tylko element nadrzędny (na przykład układ liniowy).

Jeśli masz wielu rodziców wewnątrz elementu podrzędnego ScrollView, jedynym rozwiązaniem, które znalazłem, jest wywołanie requestChildFocus w widoku nadrzędnym:

editText.getParent().requestChildFocus(editText, editText);

ale w tym przypadku nie możesz mieć płynnego przewijania.

Mam nadzieję, że ta odpowiedź może pomóc komuś z tym samym problemem.

Mattia Ruggiero
źródło
1
@JohnT Cieszę się, że ci pomogło :)
Mattia Ruggiero
20

Użyj czegoś takiego:

mScrollView.scrollBy(10, 10);

lub

mScrollView.scrollTo(10, 10);
Srichand Yella
źródło
8

Jeśli chcesz przewijać od razu, możesz użyć:

ScrollView scroll= (ScrollView)findViewById(R.id.scroll);
scroll.scrollTo(0, scroll.getBottom());

            OR

scroll.fullScroll(View.FOCUS_DOWN);

            OR

scroll.post(new Runnable() {            
    @Override
    public void run() {
           scroll.fullScroll(View.FOCUS_DOWN);              
    }
});

Lub jeśli chcesz przewijać płynnie i powoli, aby móc tego użyć:

private void sendScroll(){
        final Handler handler = new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {Thread.sleep(100);} catch (InterruptedException e) {}
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        scrollView.fullScroll(View.FOCUS_DOWN);
                    }
                });
            }
        }).start();
    }
Maddy
źródło
co robi ten catchblok?
John Sardinha
1
Blok Catch służy do przechwytywania wyjątków podczas przewijania, jeśli takie zostaną znalezione.
Maddy
5

** aby przewinąć do żądanej wysokości. Mam dobre rozwiązanie **

                scrollView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        scrollView.scrollBy(0, childView.getHeight());
                    }
                }, 100);
Vikas Chauhan
źródło
4

Mam to do pracy, aby przewinąć do dołu ScrollView (z TextView w środku):

(Umieściłem to na metodzie, która aktualizuje TextView)

final ScrollView myScrollView = (ScrollView) findViewById(R.id.myScroller);
    myScrollView.post(new Runnable() {
    public void run() {
        myScrollView.fullScroll(View.FOCUS_DOWN);
    }
});
Ohiovr
źródło
4

Tak, możesz.

Powiedzmy, że masz jeden, Layouta wewnątrz niego masz wiele Views. Więc jeśli chcesz przewinąć do dowolnego Viewprogramistycznie, musisz napisać następujący fragment kodu:

Na przykład:

content_main.xml

<ScrollView
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <Button
            android:id="@+id/btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/txtView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>
</ScrollView>

MainActivity.java

ScrollView scrollView = (ScrollView) findViewById(R.id.scrollView);
Button btn = (Button) findViewById(R.id.ivEventBanner);
TextView txtView = (TextView) findViewById(R.id.ivEditBannerImage);

Jeśli chcesz przewinąć do konkretnego View, powiedzmy txtview , w tym przypadku po prostu napisz:

scrollView.smoothScrollTo(txtView.getScrollX(),txtView.getScrollY());

Gotowe.

Pankaj Lilan
źródło
3

Uwaga: jeśli jesteś już w wątku, musisz utworzyć nowy wątek postu, lub nie przewijaj nowej długiej wysokości do pełnego końca (dla mnie). Na przykład:

void LogMe(final String s){
    runOnUiThread(new Runnable() {
        public void run() {
            connectionLog.setText(connectionLog.getText() + "\n" + s);
            final ScrollView sv = (ScrollView)connectLayout.findViewById(R.id.scrollView);
            sv.post(new Runnable() {
                public void run() {
                    sv.fullScroll(sv.FOCUS_DOWN);
                    /*
                    sv.scrollTo(0,sv.getBottom());
                    sv.scrollBy(0,sv.getHeight());*/
                }
            });
        }
    });
}
djdance
źródło
3

Dodanie kolejnej odpowiedzi, która nie zawiera współrzędnych.

Spowoduje to skupienie się na żądanym widoku (ale nie na najwyższej pozycji):

  yourView.getParent().requestChildFocus(yourView,yourView);

public void RequestChildFocus (Wyświetl dziecko, skoncentrowany na widoku)

child - dziecko tego ViewParent, które chce się skupić. Ten widok będzie zawierał aktywny widok. Niekoniecznie jest to pogląd, który faktycznie się skupia.

skoncentrowany - widok będący potomkiem dziecka, który faktycznie jest skupiony

Swas_99
źródło
Dokładnie to, czego potrzebowałem, dziękuję. Pierwsze żądanie fokusu powoduje przewijanie widoku, a następnie scrollView.smoothScrollTo (0, scrollView.getChildAt (0) .getBottom ());
Vulovic Vukasin,
3

po prostu przewiń stronę:

ScrollView sv = (ScrollView) findViewById(your_scroll_view);
sv.pageScroll(View.FOCUS_DOWN);
Kirill Vashilo
źródło
2

Każdy publikuje tak skomplikowane odpowiedzi.

Znalazłem łatwą odpowiedź, ładnie przewijając do dołu:

final ScrollView myScroller = (ScrollView) findViewById(R.id.myScrollerView);

// Scroll views can only have 1 child, so get the first child's bottom,
// which should be the full size of the whole content inside the ScrollView
myScroller.smoothScrollTo( 0, myScroller.getChildAt( 0 ).getBottom() );

I jeśli to konieczne, możesz umieścić drugą linię kodu powyżej w pliku wykonywalnym:

myScroller.post( new Runnable() {
    @Override
    public void run() {
        myScroller.smoothScrollTo( 0, myScroller.getChildAt( 0 ).getBottom() );
    }
}

Znalezienie tego prostego rozwiązania wymagało wielu badań i zabawy. Mam nadzieję, że tobie też pomoże! :)

Nalorin
źródło
1

Używałem Runnable z sv.fullScroll (View.FOCUS_DOWN); Działa idealnie w przypadku bezpośredniego problemu, ale ta metoda sprawia, że ​​ScrollView przejmuje fokus z całego ekranu, jeśli sprawisz, że automatyczne przewijanie będzie się dziać za każdym razem, żaden EditText nie będzie mógł otrzymywać informacji od użytkownika, moje rozwiązanie używa innego kodu pod runnable:

sv.scrollTo (0, sv.getBottom () + sv.getScrollY ());

robiąc to samo bez utraty koncentracji na ważnych poglądach

Pozdrowienia.

Sebasu
źródło
0

to działa dla mnie

mScrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mScrollView.post(new Runnable() {
                public void run() {
                    mScrollView.fullScroll(View.FOCUS_DOWN);
                }
            });
        }
    });
ali asadi
źródło
0
private int totalHeight = 0;

ViewTreeObserver ScrollTr = loutMain.getViewTreeObserver();
ScrollTr.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            loutMain.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        } else {
            loutMain.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
        TotalHeight = loutMain.getMeasuredHeight();

    }
});

scrollMain.smoothScrollTo(0, totalHeight);
P. Patel
źródło
0
I had to create Interface

public interface ScrollViewListener {
    void onScrollChanged(ScrollViewExt scrollView, 
                         int x, int y, int oldx, int oldy);
}    

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;

public class CustomScrollView extends ScrollView {
    private ScrollViewListener scrollViewListener = null;
    public ScrollViewExt(Context context) {
        super(context);
    }

    public CustomScrollView (Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public CustomScrollView (Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (scrollViewListener != null) {
            scrollViewListener.onScrollChanged(this, l, t, oldl, oldt);
        }
    }
}




<"Your Package name ".CustomScrollView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusableInTouchMode="true"
    android:scrollbars="vertical">

    private CustomScrollView scrollView;

scrollView = (CustomScrollView)mView.findViewById(R.id.scrollView);
        scrollView.setScrollViewListener(this);


    @Override
    public void onScrollChanged(ScrollViewExt scrollView, int x, int y, int oldx, int oldy) {
        // We take the last son in the scrollview
        View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1);
        int diff = (view.getBottom() - (scrollView.getHeight() + scrollView.getScrollY()));

        // if diff is zero, then the bottom has been reached
        if (diff == 0) {
                // do stuff
            //TODO keshav gers
            pausePlayer();
            videoFullScreenPlayer.setVisibility(View.GONE);

        }
    }
Keshav Gera
źródło