Android: ScrollView fuerza hacia abajo

200

Me gustaría que un ScrollView comenzara en la parte inferior. Cualquier metodo?

Noah Seidman
fuente
1
Creo que es solo scrollTo (), sí, acabo de comprobar los documentos de desarrollo para ScrollView. Pan comido.
Noah Seidman

Respuestas:

274

scroll.fullScroll(View.FOCUS_DOWN) También debería funcionar.

Pon esto en un scroll.Post(Runnable run)

Código Kotlin

scrollView.post {
   scrollView.fullScroll(View.FOCUS_DOWN)
}
CommonsWare
fuente
66
Eso no parece hacer nada, ¿alguna sugerencia? Lo probé en onCreate y luego en onClick de un botón.
RichardJohnn
No parece funcionar para cambiar la orientación. De lo contrario, está funcionando.
Prashant
1
Esto no funciona si el tamaño del diseño ha cambiado justo antes de llamarlo. Necesita ser publicado en su lugar.
MLProgrammer-CiM
2
Esto y más abajo, no funcionará hasta que dediques algo de tiempo a que la vista se infle completamente, simplemente simplificando una respuesta adecuada. scrollView.postDelayed (new Runnable () {@Override public void run () {scrollView.fullScroll (View.FOCUS_UP // Or Down);}}, 1000);
EngineSense
scroll.fullScroll (View.FOCUS_DOWN) conducirá al cambio de enfoque. Eso traerá un comportamiento extraño cuando haya más de una vista enfocable, por ejemplo, dos EditText. Verifique otra solución que proporciono en la parte inferior.
Peacepassion
332

deberías ejecutar el código dentro del scroll.post así:

scroll.post(new Runnable() {            
    @Override
    public void run() {
           scroll.fullScroll(View.FOCUS_DOWN);              
    }
});
hungson175
fuente
44
hay alguna manera sin perder el elemento actual de foco, cuando hago esto pierdo el foco de mi elemento actual (diferente de scrollview)
rkmax
2
Esto es necesario solo en los casos en que el diseño aún no se ha medido y diseñado (por ejemplo, si lo ejecuta en onCreate). En casos como presionar un botón, .post () no es necesario.
Patrick Boos
12
Si no desea enfocarse en ScrollView, puede usar scroll.scrollTo(0, scroll.getHeight());para saltar al fondo, o scroll.smoothScrollTo(0, scroll.getHeight());para un desplazamiento más suave
yuval el
¿No es este código una posible pérdida de memoria? Se crea un Runnable anónimo que contiene una referencia a una vista de actividad (desplazamiento). Si la actividad se destruye mientras el ejecutable está ejecutando su tarea, se filtrará una referencia a la vista de desplazamiento, ¿no?
Jenever
En Kotlin:scrollView.post { scrollView.fullScroll(View.FOCUS_DOWN) }
Albert Vila Calvo
94

scroll.fullScroll(View.FOCUS_DOWN)conducirá al cambio de enfoque. Eso traerá un comportamiento extraño cuando haya más de una vista enfocable, por ejemplo, dos EditText. Hay otra forma de esta pregunta.

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

Esto funciona bien

Extensión Kotlin

fun ScrollView.scrollToBottom() {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)        
    smoothScrollBy(0, delta)
}
Pasión por la paz
fuente
Me alegro de no tener que perder más tiempo en esto. Justo lo que necesitaba
Alexandre G
66
Esto debería tener más votos a favor. Es la mejor respuesta con diferencia.
Eric Lange
1
Esta es la mejor respuesta presente aquí.
puntero nulo
1
Intenté todo lo demás en esta página, incluso las cosas debajo de esto. Esto fue lo único que funcionó, y no hace que mi EditText pierda el foco. Gracias.
Joel
Si necesita desplazarse hacia abajo mientras se muestra el teclado, combine este código con esta biblioteca . Funciona de maravilla.
wonsuc
47

A veces scrollView.post no funciona

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

PERO si usa scrollView.postDelayed, definitivamente funcionará

 scrollView.postDelayed(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    },1000);
Ajay Shrestha
fuente
Gracias por la identificación. postDelayed es una mejor solución.
Prashant
@Prashant :) :) :)
Ajay Shrestha
1
Solo recuerda que debes deshacerte de tu Runnable cuando termines la actividad
FabioR
38

Lo que funcionó mejor para mí es

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
fuente
Intenté esto, pero el algoritmo aquí está mal. Mira mi respuesta en la parte inferior por favor.
Peacepassion
28

Incremento para trabajar perfectamente.

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

Nota

Esta respuesta es una solución para versiones realmente antiguas de Android. Hoy postDelayedno tiene más ese error y debería usarlo.

ademar111190
fuente
3
No más de dos, pero esto funciona bien en mi teléfono (LG JellyBean 4.1.2 Optimus G).
Youngjae
9
¿Por qué no usar scrollView.postDelayed (runnable, 100)?
Matt Wolfe el
1
@MattWolfe en ese momento no funcionaba en algunas versiones antiguas de Android. Pero hoy esta respuesta está en desuso en absoluto.
ademar111190
44
¡Por el amor de Dios, usa scrollView.postDelayed (ejecutable, 100)! :)
Alex Lockwood
1
Agregué una nota @ AlexLockwood Espero que la gente use el postDelayed:)
ademar111190
4

Lo intenté con éxito.

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

Cuando la vista aún no está cargada, no puede desplazarse. Puede hacerlo 'más tarde' con una publicación o llamada de suspensión como se indicó anteriormente, pero esto no es muy elegante.

Es mejor planificar el desplazamiento y hacerlo en el siguiente onLayout (). Código de ejemplo aquí:

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

Franco
fuente
3

Una cosa a considerar es qué NO configurar. Asegúrese de que sus controles secundarios, especialmente los controles EditText, no tengan establecida la propiedad RequestFocus. Esta puede ser una de las últimas propiedades interpretadas en el diseño y anulará la configuración de gravedad en sus padres (el diseño o ScrollView).

Epsilon3
fuente
3

Aquí hay otras formas de desplazarse hacia abajo

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

Utilizando

Si desplaza la vista ya presentada

my_scroll_view.scrollToBottom()

Si su vista de desplazamiento no está terminada (por ejemplo: se desplaza hacia abajo en onCreateMétodo de actividad ...)

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

No es exactamente la respuesta a la pregunta, pero necesitaba desplazarme hacia abajo tan pronto como un EditText tuviera el foco. Sin embargo, la respuesta aceptada haría que el ET también pierda el foco de inmediato (supongo que con ScrollView).

Mi solución fue la siguiente:

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

De hecho, encontré que llamar a fullScroll dos veces es el truco:

myScrollView.fullScroll(View.FOCUS_DOWN);

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

Puede tener algo que ver con la activación del método post () justo después de realizar el primer desplazamiento (sin éxito). Creo que este comportamiento ocurre después de cualquier llamada a un método anterior en myScrollView, por lo que puede intentar reemplazar el primer método fullScroll () por cualquier otra cosa que pueda ser relevante para usted.

BarLr
fuente
0

Usar hay otra forma genial de hacer esto con las corutinas de Kotlin. La ventaja de usar una rutina opuesta a un controlador con un ejecutable (post / postDelayed) es que no activa un hilo costoso para ejecutar una acción retrasada.

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

Es importante especificar el HandlerContext de la rutina como IU; de lo contrario, es posible que no se invoque la acción retrasada desde el hilo de la IU.

Phaestion
fuente
0

En esos casos estaban usando solo scroll.scrollTo (0, sc.getBottom ()) no funciona, úselo usando úselo scroll.post

Ejemplo:

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

Una posible razón de por qué scroll.fullScroll(View.FOCUS_DOWN)podría no funcionar incluso envuelto .post()es que la vista no se presenta. En este caso, View.doOnLayout () podría ser una mejor opción:

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

O, algo más elaborado para las almas valientes: https://chris.banes.dev/2019/12/03/suspending-views/

Ghedeon
fuente