Android: ScrollView wymusza przejście na dół

200

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

Noah Seidman
źródło
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)
}
CommonsWare
źródło
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);              
    }
});
hungson175
źródło
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)
}
peacepassion
źródło
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);
Ajay Shrestha
źródło
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());
     }
});
https
źródło
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ć.

ademar111190
źródło
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);
Yusuf Yaşar
źródło
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

Szczery
źródło
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).

Epsilon3
źródło
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()          
}
Phan Van Linh
źródło
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();
        }
    }
});
Teo Inke
źródło
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.

BarLr
źródło
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.

Phaestion
źródło
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);
  } 
});
nnyerges
źródło
0

Jednym z możliwych powodów, dla których scroll.fullScroll(View.FOCUS_DOWN)może nie działać, nawet gdy jest opakowany, .post()jest brak widoku. W takim przypadku lepszym rozwiązaniem może być View.doOnLayout () :

scroll.doOnLayout(){
    scroll.fullScroll(View.FOCUS_DOWN)
}

Lub coś bardziej opracowanego dla odważnych dusz: https://chris.banes.dev/2019/12/03/suspending-views/

Ghedeon
źródło