Android: ScrollView nach unten zwingen

200

Ich möchte, dass eine ScrollView ganz unten beginnt. Irgendwelche Methoden?

Noah Seidman
quelle
1
Ich denke, es ist nur scrollTo (), ja, ich habe gerade die Entwicklungsdokumente für ScrollView überprüft. Kinderleicht.
Noah Seidman

Antworten:

274

scroll.fullScroll(View.FOCUS_DOWN) sollte auch funktionieren.

Setzen Sie dies in ein scroll.Post(Runnable run)

Kotlin Code

scrollView.post {
   scrollView.fullScroll(View.FOCUS_DOWN)
}
CommonsWare
quelle
6
Das scheint nichts zu tun, irgendwelche Vorschläge? Ich habe es bei onCreate und später beim onClick einer Schaltfläche versucht.
Richard Johnn
Es scheint nicht daran zu arbeiten, die Orientierung zu ändern. Ansonsten funktioniert es.
Prashant
1
Dies funktioniert nicht, wenn sich die Layoutgröße unmittelbar vor dem Aufruf geändert hat. Es muss stattdessen gepostet werden.
MLProgrammer-CiM
2
Dies und weiter unten funktioniert erst, wenn Sie der Ansicht etwas Zeit geben, sich vollständig aufzublasen. Dies vereinfacht lediglich die Antwort von Ademar. scrollView.postDelayed (new Runnable () {@Override public void run () {scrollView.fullScroll (View.FOCUS_UP // Or Down);}}, 1000);
EngineSense
scroll.fullScroll (View.FOCUS_DOWN) führt zu einer Änderung des Fokus. Dies führt zu einem merkwürdigen Verhalten, wenn mehr als eine fokussierbare Ansicht vorhanden ist, z. B. zwei EditText. Überprüfen Sie eine andere Lösung, die ich unten anbiete.
Friedensleidenschaft
332

Sie sollten den Code in der scroll.post wie folgt ausführen:

scroll.post(new Runnable() {            
    @Override
    public void run() {
           scroll.fullScroll(View.FOCUS_DOWN);              
    }
});
hungson175
quelle
4
Es gibt einen Weg, ohne den Fokus des aktuellen Elements zu verlieren. Wenn ich dies tue, verliere ich den Fokus meines aktuellen Elements (anders als in der Bildlaufansicht)
rkmax
2
Dies ist nur in Fällen erforderlich, in denen das Layout noch nicht gemessen und gestaltet wurde (z. B. wenn Sie es in onCreate ausführen). In Fällen wie dem Drücken einer Taste wird .post () nicht benötigt.
Patrick Boos
12
Wenn Sie sich nicht auf die ScrollView konzentrieren möchten, können Sie verwenden, scroll.scrollTo(0, scroll.getHeight());um nach unten zu springen, oder scroll.smoothScrollTo(0, scroll.getHeight());für eine glattere Schriftrolle
yuval
Ist dieser Code nicht ein möglicher Speicherverlust? Es wird eine anonyme ausführbare Datei erstellt, die einen Verweis auf eine Aktivitätsansicht (Bildlaufansicht) enthält. Wenn die Aktivität zerstört wird, während die ausführbare Datei ihre Aufgabe ausführt, wird ein Verweis auf die Bildlaufansicht verloren, nicht wahr?
Jenever
In Kotlin:scrollView.post { scrollView.fullScroll(View.FOCUS_DOWN) }
Albert Vila Calvo
94

scroll.fullScroll(View.FOCUS_DOWN)wird zu einer Änderung des Fokus führen. Dies führt zu einem merkwürdigen Verhalten, wenn mehr als eine fokussierbare Ansicht vorhanden ist, z. B. zwei EditText. Es gibt einen anderen Weg für diese Frage.

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

Das funktioniert gut.

Kotlin-Erweiterung

fun ScrollView.scrollToBottom() {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)        
    smoothScrollBy(0, delta)
}
Friedensleidenschaft
quelle
Ich bin so froh, dass ich keine Zeit mehr damit verschwenden musste. Genau das, was ich brauchte
Alexandre G
6
Dies sollte mehr positive Stimmen haben. Es ist bei weitem die beste Antwort.
Eric Lange
1
Dies ist die beste Antwort hier.
Zeiger ungültig machen
1
Versuchte alles andere auf dieser Seite, sogar das Zeug weit darunter. Dies war das einzige, was funktioniert hat, und es führt nicht dazu, dass mein EditText den Fokus verliert. Danke dir.
Joel
Wenn Sie nach unten scrollen müssen, während die Tastatur angezeigt wird, kombinieren Sie diesen Code mit dieser Bibliothek . Klappt wunderbar.
Wonsuc
47

Manchmal funktioniert scrollView.post nicht

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

ABER wenn Sie scrollView.postDelayed verwenden, wird es definitiv funktionieren

 scrollView.postDelayed(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    },1000);
Ajay Shrestha
quelle
Danke für die Identifizierung. postDelayed ist eine bessere Lösung.
Prashant
@ Prashant :) :) :)
Ajay Shrestha
1
Denken Sie daran, dass Sie Ihre Runnable entsorgen müssen, wenn Sie die Aktivität beenden
FabioR
38

Was für mich am besten funktioniert hat, ist

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
quelle
Ich habe es versucht, aber der Algorithmus hier ist falsch. Überprüfen Sie bitte meine Antwort unten.
Friedensleidenschaft
28

Ich erhöhe, um perfekt zu arbeiten.

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

Hinweis

Diese Antwort ist eine Problemumgehung für wirklich alte Versionen von Android. Heute postDelayedhat der nicht mehr diesen Bug und du solltest ihn benutzen.

ademar111190
quelle
3
Nicht über zwei, aber das funktioniert gut in meinem Handy (LG JellyBean 4.1.2 Optimus G).
Youngjae
9
Warum nicht scrollView.postDelayed (lauffähig, 100) verwenden?
Matt Wolfe
1
@ MattWolfe zu der Zeit funktionierte nicht in einigen alten Versionen von Android. Aber heute ist diese Antwort überhaupt veraltet.
ademar111190
4
Verwenden Sie für die Liebe Gottes scrollView.postDelayed (lauffähig, 100)! :)
Alex Lockwood
1
Ich habe eine Notiz hinzugefügt @AlexLockwood Ich hoffe, die Leute benutzen die postDelayed:)
ademar111190
4

Ich habe das erfolgreich versucht.

scrollView.postDelayed(new Runnable() {
    @Override
    public void run() {
        scrollView.smoothScrollTo(0, scrollView.getHeight());
    }
}, 1000);
Yusuf Yaşar
quelle
3

Wenn die Ansicht noch nicht geladen ist, können Sie nicht scrollen. Sie können es "später" mit einem Post- oder Schlafanruf wie oben tun, aber dies ist nicht sehr elegant.

Es ist besser, die Schriftrolle zu planen und beim nächsten onLayout () auszuführen. Beispielcode hier:

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

Frank
quelle
3

Eine zu berücksichtigende Sache ist, was NICHT eingestellt werden soll. Stellen Sie sicher, dass für Ihre untergeordneten Steuerelemente, insbesondere für EditText-Steuerelemente, die RequestFocus-Eigenschaft nicht festgelegt ist. Dies ist möglicherweise eine der zuletzt interpretierten Eigenschaften des Layouts und überschreibt die Schwerkrafteinstellungen der übergeordneten Elemente (Layout oder ScrollView).

Epsilon3
quelle
3

Hier sind einige andere Möglichkeiten, um nach unten zu scrollen

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

Verwenden von

Wenn Sie die Bildlaufansicht bereits angelegt haben

my_scroll_view.scrollToBottom()

Wenn Ihre Bildlaufansicht nicht fertig angelegt ist (z. B.: Sie scrollen in der Aktivitätsmethode nach unten onCreate...)

my_scroll_view.post { 
   my_scroll_view.scrollToBottom()          
}
Phan Van Linh
quelle
1

Nicht genau die Antwort auf die Frage, aber ich musste nach unten scrollen, sobald ein EditText den Fokus bekam. Die akzeptierte Antwort würde jedoch dazu führen, dass der ET auch sofort den Fokus verliert (auf die ScrollView, nehme ich an).

Meine Problemumgehung war folgende:

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

Ich habe tatsächlich festgestellt, dass das zweimalige Aufrufen von fullScroll den Trick macht:

myScrollView.fullScroll(View.FOCUS_DOWN);

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

Dies hat möglicherweise etwas mit der Aktivierung der post () -Methode direkt nach dem ersten (nicht erfolgreichen) Bildlauf zu tun. Ich denke, dieses Verhalten tritt nach jedem vorherigen Methodenaufruf in myScrollView auf, sodass Sie versuchen können, die erste fullScroll () -Methode durch etwas anderes zu ersetzen, das für Sie relevant sein könnte.

BarLr
quelle
0

Es gibt eine andere coole Möglichkeit, dies mit Kotlin-Coroutinen zu tun. Der Vorteil der Verwendung einer Coroutine im Gegensatz zu einem Handler mit einer ausführbaren Datei (post / postDelayed) besteht darin, dass kein teurer Thread zum Ausführen einer verzögerten Aktion gestartet wird.

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

Es ist wichtig, den HandlerContext der Coroutine als Benutzeroberfläche anzugeben, da sonst die verzögerte Aktion möglicherweise nicht vom UI-Thread aufgerufen wird.

Phaestion
quelle
0

In diesen Fällen würde nur scroll.scrollTo (0, sc.getBottom ()) nicht funktionieren, verwenden Sie es mit scroll.post

Beispiel:

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

Ein möglicher Grund, warum scroll.fullScroll(View.FOCUS_DOWN)möglicherweise nicht einmal eingepackt funktioniert, .post()ist, dass die Ansicht nicht angelegt ist. In diesem Fall könnte View.doOnLayout () eine bessere Option sein:

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

Oder etwas Ausführlicheres für die tapferen Seelen: https://chris.banes.dev/2019/12/03/suspending-views/

Ghedeon
quelle