Android: ScrollView wymusza przejście na dół


200

Chciałbym, aby ScrollView zaczął się od samego początku. Jakieś metody?


1
Myślę, że to tylko scrollTo (), tak, właśnie sprawdziłem dokumenty deweloperów dla ScrollView. Bułka z masłem.
Noah Seidman

Odpowiedzi:


274

scroll.fullScroll(View.FOCUS_DOWN) powinien również działać.

Umieść to w scroll.Post(Runnable run)

Kod Kotlin

scrollView.post {
   scrollView.fullScroll(View.FOCUS_DOWN)
}

6
To wydaje się nic nie robić, jakieś sugestie? Wypróbowałem to na onCreate, a później na onClick przycisku.
RichardJohnn

Wydaje się, że nie działa na zmianę orientacji. W przeciwnym razie działa.
Prashant,

1
Nie działa to, jeśli rozmiar układu zmienił się tuż przed wywołaniem. Zamiast tego należy go opublikować.
MLProgrammer-CiM

2
To i poniżej nie będzie działać, dopóki nie poświęcisz trochę czasu na pełne powiększenie widoku, po prostu upraszczając odpowiedź ademar. scrollView.postDelayed (new Runnable () {@Override public void run () {scrollView.fullScroll (View.FOCUS_UP // Lub w dół);}}, 1000);
EngineSense

scroll.fullScroll (View.FOCUS_DOWN) doprowadzi do zmiany ostrości. Spowoduje to dziwne zachowanie, gdy istnieje więcej niż jeden widok z możliwością ustawiania ostrości, np. Dwa EditText. Sprawdź inne rozwiązanie, które podaję na dole.
peacepassion

332

powinieneś uruchomić kod w scroll.post w następujący sposób:

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

4
jest jakiś sposób bez utraty elementu bieżącego fokusa, kiedy to robię, tracę fokus mojego bieżącego elementu (innego niż scrollview)
rkmax 21.09.14

2
Jest to potrzebne tylko w przypadkach, gdy układ nie został jeszcze zmierzony i ułożony (na przykład, jeśli uruchomisz go w programie onCreate). W przypadkach takich jak naciśnięcie przycisku funkcja .post () nie jest potrzebna.
Patrick Boos,

12
Jeśli nie chcesz skupiać się na ScrollView, możesz użyć przycisku, scroll.scrollTo(0, scroll.getHeight());aby przejść do dołu lub scroll.smoothScrollTo(0, scroll.getHeight());płynniejszego przewijania
yuval

Czy ten kod nie jest możliwym wyciekiem pamięci? Tworzona jest anonimowa Runnable, która zawiera odniesienie do widoku aktywności (przewijania). Jeśli działanie zostanie zniszczone w trakcie wykonywania zadania przez runnable, wycieknie odwołanie do widoku przewijania, nie?
Jenever

W Kotlinie:scrollView.post { scrollView.fullScroll(View.FOCUS_DOWN) }
Albert Vila Calvo

94

scroll.fullScroll(View.FOCUS_DOWN)doprowadzi do zmiany ostrości. Spowoduje to dziwne zachowanie, gdy istnieje więcej niż jeden widok z możliwością ustawiania ostrości, np. Dwa EditText. Jest inny sposób na to pytanie.

    View lastChild = scrollLayout.getChildAt(scrollLayout.getChildCount() - 1);
    int bottom = lastChild.getBottom() + scrollLayout.getPaddingBottom();
    int sy = scrollLayout.getScrollY();
    int sh = scrollLayout.getHeight();
    int delta = bottom - (sy + sh);

    scrollLayout.smoothScrollBy(0, delta);

To działa dobrze.

Rozszerzenie Kotlin

fun ScrollView.scrollToBottom() {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)        
    smoothScrollBy(0, delta)
}

Cieszę się, że nie musiałem tracić na to więcej czasu. Właśnie tego potrzebowałem
Alexandre G

6
To powinno mieć więcej głosów pozytywnych. Jak dotąd najlepsza odpowiedź.
Eric Lange,

1
To najlepsza obecna odpowiedź tutaj.
void pointer

1
Próbowałem wszystkiego innego na tej stronie, nawet tych poniżej. To była jedyna rzecz, która działała i nie powoduje, że mój EditText traci koncentrację. Dziękuję Ci.
Joel

Jeśli musisz przewinąć w dół, gdy pokazuje się klawiatura, połącz ten kod z tą biblioteką . Działa jak marzenie.
wonsuc

47

Czasami scrollView.post nie działa

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

ALE jeśli użyjesz scrollView.postDelayed, to na pewno zadziała

 scrollView.postDelayed(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    },1000);

dzięki za identyfikację. postDelayed to lepsze rozwiązanie.
Prashant

@Prashant :) :) :)
Ajay Shrestha

1
Pamiętaj tylko, że po zakończeniu aktywności musisz zutylizować Runnable
FabioR

38

To, co działało dla mnie najlepiej, to

scroll_view.post(new Runnable() {
     @Override
     public void run() {
         // This method works but animates the scrolling 
         // which looks weird on first load
         // scroll_view.fullScroll(View.FOCUS_DOWN);

         // This method works even better because there are no animations.
         scroll_view.scrollTo(0, scroll_view.getBottom());
     }
});

Próbowałem tego, ale algorytm tutaj jest zły. Proszę sprawdzić moją odpowiedź na dole.
peacepassion

28

Zwiększam do perfekcji.

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

Uwaga

Ta odpowiedź jest obejściem dla naprawdę starych wersji Androida. Dzisiaj postDelayednie ma już tego błędu i powinieneś go użyć.


3
Nie powyżej dwóch, ale działa to dobrze w moim telefonie (LG JellyBean 4.1.2 Optimus G).
Youngjae

9
Dlaczego nie użyć scrollView.postDelayed (runnable, 100)?
Matt Wolfe,

1
@MattWolfe w tym czasie nie działa w niektórych starych wersjach Androida. Ale dzisiaj ta odpowiedź jest w ogóle nieaktualna.
ademar111190,

4
Na miłość boską użyj scrollView.postDelayed (runnable, 100)! :)
Alex Lockwood

1
Dodałem notatkę @AlexLockwood Mam nadzieję, że ludzie skorzystają z postDelayed:)
ademar111190,

4

próbowałem tego z sukcesem.

scrollView.postDelayed(new Runnable() {
    @Override
    public void run() {
        scrollView.smoothScrollTo(0, scrollView.getHeight());
    }
}, 1000);

3

Gdy widok nie jest jeszcze załadowany, nie można przewijać. Możesz to zrobić „później” za pomocą połączenia pocztowego lub snu, jak wyżej, ale nie jest to zbyt eleganckie.

Lepiej zaplanować zwój i zrobić to na następnej funkcji onLayout (). Przykładowy kod tutaj:

https://stackoverflow.com/a/10209457/1310343


3

Jedną rzeczą do rozważenia jest to, czego NIE należy ustawiać. Upewnij się, że formanty podrzędne, zwłaszcza formanty EditText, nie mają ustawionej właściwości RequestFocus. Może to być jedna z ostatnich interpretowanych właściwości układu i zastąpi ustawienia grawitacji na jego rodzicach (układzie lub ScrollView).


3

Oto kilka innych sposobów przewijania na dół

fun ScrollView.scrollToBottom() {
    // use this for scroll immediately
    scrollTo(0, this.getChildAt(0).height) 

    // or this for smooth scroll
    //smoothScrollBy(0, this.getChildAt(0).height)

    // or this for **very** smooth scroll
    //ObjectAnimator.ofInt(this, "scrollY", this.getChildAt(0).height).setDuration(2000).start()
}

Za pomocą

Jeśli przewijasz widok już ułożony

my_scroll_view.scrollToBottom()

Jeśli widok przewijania nie jest zakończony (np. Przewijasz w dół w onCreatemetodzie działania ...)

my_scroll_view.post { 
   my_scroll_view.scrollToBottom()          
}

1

Nie do końca odpowiedź na pytanie, ale musiałem przewinąć w dół, gdy tylko tekst EditText się skupi. Jednak zaakceptowana odpowiedź sprawiłaby, że ET również natychmiast straciłoby koncentrację (zakładam, że do ScrollView).

Moje obejście było następujące:

emailEt.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if(hasFocus){
            Toast.makeText(getActivity(), "got the focus", Toast.LENGTH_LONG).show();
            scrollView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    scrollView.fullScroll(ScrollView.FOCUS_DOWN);
                }
            }, 200);
        }else {
            Toast.makeText(getActivity(), "lost the focus", Toast.LENGTH_LONG).show();
        }
    }
});

1

Odkryłem, że dwukrotne wywołanie funkcji fullScroll:

myScrollView.fullScroll(View.FOCUS_DOWN);

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

Może to mieć coś wspólnego z aktywacją metody post () zaraz po wykonaniu pierwszego (nieudanego) przewijania. Myślę, że takie zachowanie występuje po każdym poprzednim wywołaniu metody myScrollView, więc możesz spróbować zastąpić pierwszą metodę fullScroll () inną, która może być dla ciebie odpowiednia.


0

Jest jeszcze jeden fajny sposób na zrobienie tego z karlinami Kotlin. Zaletą użycia coroutine w przeciwieństwie do Handlera z runnable (post / postDelayed) jest to, że nie uruchamia on drogiego wątku w celu wykonania akcji opóźnionej.

launch(UI){
    delay(300)
    scrollView.fullScroll(View.FOCUS_DOWN)
}

Ważne jest, aby określić HandlerContext coroutine jako interfejs użytkownika, w przeciwnym razie opóźnione działanie może nie zostać wywołane z wątku interfejsu użytkownika.


0

W takim przypadku używano tylko scroll.scrollTo (0, sc.getBottom ()) nie działa, użyj go za pomocą scroll.post

Przykład:

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

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.