¿Puedo desplazar un ScrollView mediante programación en Android?

145

¿Hay alguna manera de desplazarse ScrollViewprogramáticamente a una determinada posición?

He creado una dinámica TableLayoutque se coloca en a ScrollView. Entonces, quiero que en una acción específica (como hacer clic en un botón, etc.) la fila en particular se desplace automáticamente a una posición superior.

¿Es posible?

Arun Badole
fuente

Respuestas:

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

o

sv.scrollTo(5, 10);

Androide
fuente
43
Combinando la respuesta de ercu y un comentario al respecto, la mejor manera parece ser:mScrollView.post(new Runnable() { public void run() { mScrollView.fullScroll(View.FOCUS_DOWN); } });
gorrión
2
scrollTo () no producirá el resultado deseado. Uno debe ir con fullScroll ()
Amit Yadav
3
Un desplazamiento más agradable tiene un efecto natural: sv.smoothScrollTo (5, 10)
ivan.panasiuk
205

La respuesta de Pragna no siempre funciona, intente esto:

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

o

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

si quieres desplazarte para comenzar

mScrollView.post(new Runnable() { 
        public void run() { 
             mScrollView.fullScroll(mScrollView.FOCUS_UP);
        } 
});
ercu
fuente
28
Solía mScrollView.fullScroll(mScrollView.FOCUS_DOWN);con éxito.
amcc
3
Puedo confirmar los hallazgos de Vanthel. mScrollView.fullScroll en una publicación ejecutable hizo el truco.
AlanKley
1
Excelente! De hecho, sin el Runnable, no funcionó. Ahora funciona ! :)
Regis_AG
55
@HiteshDhamshaniya Si quieres un desplazamiento suave, inténtalo mScrollView.smoothScrollTo(0, mScrollView.getBottom());.
Mike Ortiz
1
¿Por qué necesita postaquí?
Liuting
35

Quería que scrollView se desplazara directamente después de onCreateView () (no después de, por ejemplo, hacer clic en un botón). Para que funcione, necesitaba usar un ViewTreeObserver:

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

Pero tenga en cuenta que esto se llamará cada vez que se diseñe algo (por ejemplo, si configura una vista invisible o similar), así que no olvide eliminar este oyente si ya no lo necesita con:

public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) en SDK Niv. <16

o

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

Patrick Favre
fuente
23

Aquí hay muchas buenas respuestas, pero solo quiero agregar una cosa. A veces sucede que desea desplazar su ScrollView a una vista específica del diseño, en lugar de un desplazamiento completo hacia la parte superior o inferior.

Un ejemplo simple: en un formulario de registro, si el usuario toca el botón "Registrarse" cuando no se completa un texto de edición del formulario, desea desplazarse a ese texto de edición específico para indicarle al usuario que debe completar ese campo.

En ese caso, puedes hacer algo así:

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

o, si desea un desplazamiento suave en lugar de un desplazamiento instantáneo:

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

Obviamente, puede usar cualquier tipo de vista en lugar de Editar texto. Tenga en cuenta que getBottom () devuelve las coordenadas de la vista en función de su diseño principal, por lo que todas las vistas utilizadas dentro de ScrollView deben tener solo un elemento primario (por ejemplo, un diseño lineal).

Si tiene varios padres dentro del hijo de ScrollView, la única solución que he encontrado es llamar a requestChildFocus en la vista padre:

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

pero en este caso no puede tener un desplazamiento suave.

Espero que esta respuesta pueda ayudar a alguien con el mismo problema.

Mattia Ruggiero
fuente
1
@JohnT Me alegro de que te haya ayudado :)
Mattia Ruggiero
20

Usa algo como esto:

mScrollView.scrollBy(10, 10);

o

mScrollView.scrollTo(10, 10);
Srichand Yella
fuente
8

Si desea desplazarse al instante, puede usar:

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

O si desea desplazarse suavemente y lentamente para poder usar esto:

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
fuente
¿Qué hace ese catchbloque?
John Sardinha
1
Capturar bloque es detectar excepciones durante el desplazamiento si se encuentra alguna.
Maddy
5

** para desplazarse hasta la altura deseada. Se me ocurrió una buena solución **

                scrollView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        scrollView.scrollBy(0, childView.getHeight());
                    }
                }, 100);
Vikas Chauhan
fuente
4

Obtuve esto para trabajar para desplazarme hasta la parte inferior de un ScrollView (con un TextView dentro)

(Puse esto en un método que actualiza TextView)

final ScrollView myScrollView = (ScrollView) findViewById(R.id.myScroller);
    myScrollView.post(new Runnable() {
    public void run() {
        myScrollView.fullScroll(View.FOCUS_DOWN);
    }
});
Ohiovr
fuente
4

Sí tu puedes.

Digamos que tienes uno Layouty dentro de eso, tienes muchos Views. Entonces, si desea desplazarse a cualquiera mediante Viewprogramación, debe escribir el siguiente fragmento de código:

Por ejemplo:

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

Si desea desplazarse a un específico View, digamos txtview , en este caso, simplemente escriba:

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

Y ya terminaste.

Pankaj Lilan
fuente
3

Nota: si ya está en un hilo, debe hacer un nuevo hilo de publicación, o no se desplazará a una nueva altura larga hasta el final (para mí). Por ej .:

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

Agregar otra respuesta que no implique coordenadas.

Esto traerá su vista deseada para enfocar (pero no a la posición superior):

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

public void RequestChildFocus (Ver hijo, Ver enfocado)

child : el hijo de este ViewParent que quiere enfocarse. Esta vista contendrá la vista enfocada. No es necesariamente la vista la que realmente tiene foco.

Enfocado : la vista que es descendiente de un niño que realmente tiene foco

Swas_99
fuente
Exactamente lo que necesitaba, gracias. Primero solicite el foco para su vista de desplazamiento y luego scrollView.smoothScrollTo (0, scrollView.getChildAt (0) .getBottom ());
Vulovic Vukasin
3

solo desplazamiento de página:

ScrollView sv = (ScrollView) findViewById(your_scroll_view);
sv.pageScroll(View.FOCUS_DOWN);
Kirill Vashilo
fuente
2

Todos están publicando respuestas tan complicadas.

Encontré una respuesta fácil, para desplazarme hacia abajo, muy bien:

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

Y, si es necesario, puede poner la segunda línea de código, arriba, en un ejecutable:

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

Me llevó mucha investigación y jugar para encontrar esta solución simple. ¡Espero que te ayude a ti también! :)

Nalorina
fuente
1

Estaba usando Runnable con sv.fullScroll (View.FOCUS_DOWN); Funciona perfectamente para el problema inmediato, pero ese método hace que ScrollView tome el foco de toda la pantalla, si hace que AutoScroll suceda siempre, ningún EditText podrá recibir información del usuario, mi solución fue usar un código diferente bajo el runnable:

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

haciendo lo mismo sin perder el foco en vistas importantes

saludos.

Sebasu
fuente
0

me esta funcionando

mScrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mScrollView.post(new Runnable() {
                public void run() {
                    mScrollView.fullScroll(View.FOCUS_DOWN);
                }
            });
        }
    });
Ali asadi
fuente
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
fuente
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
fuente