¿Cómo desplazarse hasta la parte superior del diseño largo de ScrollView?

162

Para parte de mi aplicación, se le presenta al usuario una lista de nombres y se le pide que los agrupe como mejor le parezca.

(Tenga en cuenta que el código ListView se copió literalmente del tutorial de Vistas de Android. Todavía no lo he personalizado a mis necesidades, solo estoy tratando de descubrir cómo hacer que esto funcione).

El diseño básico es un LinearLayout, que contiene un ScrollView (llamado "groupsScrollView" en el código a continuación), que contiene un RelativeLayout. Tengo algunos botones y texto, y luego mi ListView debajo de eso, que muestra la lista de nombres. Todo esto es más alto que el área de pantalla visible, por lo que el usuario puede desplazarse verticalmente para verlo todo.

Todo esto funciona a la perfección, excepto cuando la página se carga, siempre se desplaza previamente a la parte superior de mi ListView, en el medio de la página. El texto y los botones que he creado que le dicen al usuario qué hacer no están visibles.

Puedo tomar la pantalla y desplazarme hacia arriba, eso funciona bien, pero me gustaría que la pantalla se cargue ya que se ha desplazado hacia la parte superior. El usuario no debería tener que desplazarse hacia ARRIBA para ver la parte superior de una página recién cargada. Pero todo lo que he intentado desplazar programáticamente a la parte superior de la pantalla ha fallado.

Aquí está mi método onCreate:

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.groups);

    mainScrollView = (ScrollView)findViewById(R.id.groupsScrollView);

    //get the Bundle out of the Intent...
    Bundle extras = getIntent().getExtras();
    mNames = extras.getStringArray("mNames");

    setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, mNames));

    ListView lv = getListView();
    lv.setTextFilterEnabled(true);

    //This is the line I'm having issues with
    mainScrollView.pageScroll(View.FOCUS_UP);

    lv.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view,
            int position, long id) {
          // When clicked, show a toast with the TextView text
          Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
              Toast.LENGTH_SHORT).show();
        }
      });
}

La línea "mainScrollView.pageScroll (View.FOCUS_UP) es el problema. No causa un error, pero no parece hacer nada. He intentado scrollTo (0,0), scrollDirection (View.FOCUS_UP ), y todo lo demás que se me ocurre.

Como no recibo un error, debo suponer que estos comandos de desplazamiento funcionan realmente, pero que se desplazan hacia la parte superior de ListView, en lugar de la parte superior de ScrollView o RelativeLayout que lo contiene. Esto parece ser confirmado por la propia descripción de Google del método scrollTo (int x, int y) donde dicen "Esta versión también sujeta el desplazamiento a los límites de nuestro hijo".

Entonces, para hacer una pregunta larga aún más larga, ¿cómo cargo un montón de vistas en la pantalla contenida dentro de una Vista de desplazamiento y luego desplazo todo el programa por la parte superior de la página para que el usuario pueda interactuar con ella?

¡Gracias!

Glenn
fuente

Respuestas:

264

Tratar

mainScrollView.fullScroll(ScrollView.FOCUS_UP);

deberia de funcionar.

Roomtek
fuente
Funciona para mí también. : D
Muntasir Aonik
1
Encontré que ScrollView # fullScroll () cambia el enfoque actual. Probé con EditText.
illusionJJ
175

Tuve el mismo problema, probablemente algún tipo de error.

Incluso el fullScroll(ScrollView.FOCUS_UP)de la otra respuesta no funcionó.
Lo único que funcionó para mí fue llamar scroll_view.smoothScrollTo(0,0)justo después de que se muestra el diálogo.

Mohamed Hafez
fuente
Esto funcionó inicialmente, pero luego cuando intenté hacerlo una y otra vez, este enfoque no dio un resultado satisfactorio.
JaydeepW
16
Resuelvo desde scroll_view.smoothScrollTo (0,0), cuando tenemos listview en el lado de la vista de desplazamiento en ese momento fullScroll (ScrollView.FOCUS_UP) no funcionará.
Kirtikumar A.
1
scroll_view.smoothScrollTo (0,0) funcionó mejor para mí que mainScrollView.fullScroll (ScrollView.FOCUS_UP); ¡GRACIAS!
marienke
2
En la mayoría de los dispositivos, fullScroll (ScrollView.FOCUS_UP) funcionó, pero en el Nexus 5 y en los dispositivos en los que tenía el tamaño del texto elevado, fullSscroll se movió debajo de la barra de acción, smoothScrollTo (0,0) funcionó mejor en todos los dispositivos.
jt-gilkeson
Esto también tiene la ventaja fullScroll()de que mantiene el elemento seleccionado aún seleccionado después del movimiento. Con fullScroll(), el primer elemento en la vista de desplazamiento se volvió a seleccionar cada vez en mi caso, independientemente del elemento seleccionado antes de que el desplazamiento se moviera hacia arriba.
GeertVc
97

Tuve el mismo problema y esto lo solucionó. Espero que te ayude.

listView.setFocusable(false);
Miguel Palacios
fuente
3
Esta es la solución correcta para gridviews también. Ocurre cuando tiene más de un elemento de vista en el mismo grupo de vista, especialmente otra vista de lista en la parte superior de la lista o vista de cuadrícula. Como el adaptador notifica el subproceso de la interfaz de usuario, la vista se vuelve a crear y se desplaza hasta el primer elemento. Simplemente llame a listView.setFocusable (false) / gridView.setFocusable (false). Si lo haces desde un archivo xml, no funcionará.
omersem
Esta solución también funcionó en mi caso, tenía RecyclerView dentro de NestedScrollView, por lo que se desplazaba automáticamente hacia abajo. ¡Gracias hombre!
Nilesh Rathore
Tuve que agregar esto antes de configurar el adaptador, pero después de eso funciona de maravilla. Gracias
Comunidad
explicación perfecta !!
Borja López
Gracias a los dos Miguel y especialmente omersem para la explicación, especialmente la parte de cómo lo puedo trabajar si se ha ajustado en XML, esto me salvó algunos dolores de cabeza
buradd
53

scrollViewObject.fullScroll(ScrollView.FOCUS_UP)esto funciona bien, pero solo el problema con esta línea es que, cuando los datos se llenan en scrollViewObject, se ha llamado de inmediato. Debe esperar algunos milisegundos hasta que se llenen los datos. Prueba este código:

scrollViewObject.postDelayed(new Runnable() {
    @Override
    public void run() {
        scroll.fullScroll(ScrollView.FOCUS_UP);
    }
}, 600);

O

 scrollViewObject.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        scrollViewObject.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        scrollViewObject.fullScroll(View.FOCUS_UP);
    }
});
Mohammad Imran
fuente
Estaba lidiando con el mismo problema en el que se suponía que la vista de desplazamiento se desplazaba hacia la parte inferior de la página, ¡lo arreglé de inmediato!
Machine Tribe
1
En lugar de adivinar el número "mágico" x número de milisegundos que tendría que esperar, Ver objetos ofrece un método de publicación (Ejecutable) que podría usar que publicará el ejecutable una vez que el widget se muestre en la IU.
Ryan
@ Ryan: post (Runnable) no siempre funciona para mí en Nexus 5 (Genymotion)
Dika
post (Runnable) puede no funcionar porque si busca datos después del paso de infloración de vista, ya que primero se desplaza hacia arriba y luego los datos se completan en la vista. Por lo tanto, debe usar postDelayed (Runnable, dummyMillis) o debe usar scroll.fullScroll (ScrollView.FOCUS_UP) después de los procesos poblados de datos.
Oguzhan
Su primera solución en la que le da milis estáticos es un mal enfoque.
Malwinder Singh
35

El principal problema de todas estas soluciones válidas es que está intentando subir el desplazamiento cuando aún no está dibujado en la pantalla.

Debe esperar hasta que la vista de desplazamiento esté en la pantalla, luego subirla con cualquiera de estas soluciones. Esta es una mejor solución que una demora posterior, porque no le importa el retraso.

    // Wait until my scrollView is ready
    scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // Ready, move up
            scrollView.fullScroll(View.FOCUS_UP);
        }
    });
Pelanes
fuente
77
Buena solución: no se olvide de eliminar Global Listener al final de la onGlobalLayoutllamada al método scrollView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
Nilhcem
30

Muy fácil

    ScrollView scroll = (ScrollView) findViewById(R.id.addresses_scroll);
    scroll.setFocusableInTouchMode(true);
    scroll.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
CommonSenseCode
fuente
3
para mí no funcionó (la tercera línea), la solución fue: scroll.fullScroll (View.FOCUS_UP); (con incluir sus primeras 2 líneas)
medskill
@medskill, Hola, ¿escribiste esto en tu archivo xml? Creo que esto solo funciona en onCreate().
desconocido
@ imknownJ.Kimu funciona para mí en un archivo xml
Paglian
Esto funcionó para mí. Necesitas tanto la segunda como la tercera línea. No funcionaría en el XML para mí.
ET
2
¡Te besaría si pudiera! Pasé 1-2 horas en esto. La mejor cuando esperaba que se cargaran dos vistas de lista y no quería centrarse en ellas. Lo agregó a onResume ().
John T
24

Enfrenté el mismo problema cuando uso Scrollview dentro de View Flipper o Dialog, ese caso scrollViewObject.fullScroll(ScrollView.FOCUS_UP)devuelve falso, por lo que ese caso scrollViewObject.smoothScrollTo(0, 0)me funcionó

Scroll Focus Top

sravan
fuente
19
 final ScrollView scrollview = (ScrollView)findViewById(R.id.selected_place_layout_scrollview);

         scrollview.post(new Runnable() { 
                public void run() { 
                    scrollview.scrollTo(0, 0); 
                } 
            }); 
Mladen Rakonjac
fuente
9
runOnUiThread( new Runnable(){
   @Override
   public void run(){
      mainScrollView.fullScroll(ScrollView.FOCUS_UP);
   }
}
traeper
fuente
9

Esto me funcionó

scroll_view.smoothScrollTo(0,0); // scroll to top of screen
Pankaj Talaviya
fuente
6

Esto es forzar desplazamiento para scrollview :

            scrollView.post(new Runnable() {
                @Override
                public void run() {
                    scrollView.scrollTo(0, 0);
                    scrollView.pageScroll(View.FOCUS_UP);
                    scrollView.smoothScrollTo(0,0);
                }
            });
Hadi Note
fuente
4
scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        // Ready, move up
        scrollView.fullScroll(View.FOCUS_UP);
    }
});

fuente
1

Solucioné mi problema en Kotlin así:

scrollview.isFocusableInTouchMode = true
scrollview.fullScroll(View.FOCUS_UP)
scrollview.smoothScrollTo(0,0)
MaK
fuente
0
@SuppressWarnings({ "deprecation", "unchecked" })
public void swipeTopToBottom(AppiumDriver<MobileElement> driver) 
                    throws InterruptedException {
       Dimension dimensions = driver.manage().window().getSize();
        Double screenHeightStart = dimensions.getHeight() * 0.30;
        int scrollStart = screenHeightStart.intValue();
        System.out.println("s="+scrollStart);
        Double screenHeightEnd = dimensions.getHeight()*0.90;
        int scrollEnd = screenHeightEnd.intValue();
        driver.swipe(0,scrollStart,0,scrollEnd,2000);
        CommonUtils.threadWait(driver, 3000);
    }
Ajeet Gour
fuente
esto se ejecutará seguro,
Ajeet Gour
Proporcione una breve explicación sobre cómo esta respuesta resuelve el problema.
Ayberk Özgür