HorizontalScrollView: desplazamiento automático para finalizar cuando se agregan nuevas vistas?

Tengo un HorizontalScrollView que contiene un LinearLayout. En la pantalla tengo un botón que agregará nuevas vistas a LinearLayout en tiempo de ejecución, y me gustaría que la vista de desplazamiento para desplazarse hasta el final de la lista cuando se agrega una nueva vista.

Casi lo tengo trabajando – excepto que siempre se desplaza una vista de la última vista. Parece que se está desplazando sin calcular primero la inclusión de la nueva vista.

En mi aplicación estoy usando un objeto de vista personalizado, pero he hecho una pequeña aplicación de prueba que utiliza ImageView y tiene el mismo síntoma. He intentado varias cosas como requestLayout () en el Layout y ScrollView, he intentado scrollTo (Integer.MAX_VALUE) y se desplazó en el netherverse 🙂 ¿Estoy violando un problema de hilo de interfaz de usuario o algo así?

  • Almiar

======

public class Main extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button b = (Button) findViewById(R.id.addButton); b.setOnClickListener(new AddListener()); add(); } private void add() { LinearLayout l = (LinearLayout) findViewById(R.id.list); HorizontalScrollView s = (HorizontalScrollView) findViewById(R.id.scroller); ImageView i = new ImageView(getApplicationContext()); i.setImageResource(android.R.drawable.btn_star_big_on); l.addView(i); s.fullScroll(HorizontalScrollView.FOCUS_RIGHT); } private class AddListener implements View.OnClickListener { @Override public void onClick(View v) { add(); } } } 

Diseño XML:

  <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <HorizontalScrollView android:id="@+id/scroller" android:layout_width="wrap_content" android:layout_height="wrap_content" android:scrollbarSize="50px"> <LinearLayout android:id="@+id/list" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="4px"/> </HorizontalScrollView> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_gravity="center"> <Button android:id="@+id/addButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:paddingLeft="80px" android:paddingRight="80px" android:paddingTop="40px" android:paddingBottom="40px" android:text="Add"/> </LinearLayout> </LinearLayout> 

Creo que hay un problema de tiempo. El diseño no se realiza cuando se agrega una vista. Se solicita y se hace poco tiempo después. Cuando llame a fullScroll inmediatamente después de agregar la vista, el ancho de la linea lineal no ha tenido la oportunidad de expandirse.

Prueba a sustituir:

 s.fullScroll(HorizontalScrollView.FOCUS_RIGHT); 

con:

 s.postDelayed(new Runnable() { public void run() { s.fullScroll(HorizontalScrollView.FOCUS_RIGHT); } }, 100L); 

El corto retraso debe dar al sistema suficiente tiempo para asentarse.

PS Puede ser suficiente simplemente retrasar el desplazamiento hasta después de la iteración actual del bucle de interfaz de usuario. No he probado esta teoría, pero si es correcto, sería suficiente hacer lo siguiente:

 s.post(new Runnable() { public void run() { s.fullScroll(HorizontalScrollView.FOCUS_RIGHT); } }); 

Me gusta esto mejor porque la introducción de un retraso arbitrario parece hacky para mí (a pesar de que era mi sugerencia).

Sólo otra sugerencia, ya que esta pregunta me ayudó mucho :).

Usted puede poner un oyente cuando la vista ha terminado su fase de diseño, y justo después de hacer el fullScroll althought necesitará ampliar la clase para eso.

Sólo hice esto porque quería desplazarme a una sección justo después de onCreate () para evitar que parpadee desde el punto de partida hasta el punto de desplazamiento.

Algo como:

 public class PagerView extends HorizontalScrollView { private OnLayoutListener mListener; ///... private interface OnLayoutListener { void onLayout(); } public void fullScrollOnLayout(final int direction) { mListener = new OnLayoutListener() { @Override public void onLayout() { fullScroll(direction) mListener = null; } }; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if(mListener != null) mListener.onLayout(); } } 

Estoy de acuerdo con @monxalo y @ granko87 que el mejor enfoque es con un oyente en lugar de hacer una suposición de que el diseño será completa si dejamos pasar una cantidad arbitraria de tiempo.

En caso de que, al igual que yo, no necesite usar una subclase horizontalScrollView personalizada, sólo puede agregar un OnLayoutChangeListener para mantener las cosas simples:

 mTagsScroller.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { mTagsScroller.removeOnLayoutChangeListener(this); mTagsScroller.fullScroll(View.FOCUS_RIGHT); } }); 

Utilice el método View smoothScrollTo

 postDelayed(new Runnable() { public void run() { scrollView.smoothScrollTo(newView.getLeft(), newView.getTop()); } }, 100L); 

Usted necesita poner en un runnable así que usted da tiempo al proceso de la disposición para colocar la nueva visión

Esto es lo que hice.

 //Observe for a layout change ViewTreeObserver viewTreeObserver = yourLayout.getViewTreeObserver(); if (viewTreeObserver.isAlive()) { viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { yourHorizontalScrollView.fullScroll(HorizontalScrollView.FOCUS_RIGHT); } }); } 

Creo que el mejor enfoque es el publicado por monxalo porque no se puede saber cuánto tiempo se tarda hasta que el diseño se hace. Lo intenté y funciona perfectamente. La única diferencia es que agregé sólo una fila a mi vista de desplazamiento horizontal personalizada:

 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); this.fullScroll(HorizontalScrollView.FOCUS_RIGHT); } 

Utilice debajo del código para desplazamiento horizontal { Desplácese a la derecha }

 view.post(new Runnable() { @Override public void run() { ((HorizontalScrollView) Iview .findViewById(R.id.hr_scroll)) .fullScroll(HorizontalScrollView.FOCUS_RIGHT); } }); 
  • ¿La mejor manera de crear Barra de progreso segmentada?
  • Android - Cómo utilizar la cámara getSupportedPreviewSizes () para la orientación vertical
  • ¿Cómo puedo hacer que un TextView se vea como un botón?
  • Android: IllegalStateException - ¿Cuándo es lanzado?
  • Android: ¿Cómo encontrar el ancho y la altura de la pantalla?
  • Cómo usar la barra de desplazamiento y rápido Desplácese a NestedScrollView
  • Suspender subprocesos al ejecutar múltiples AsyncTasks en fragmentos anidados y hace que la aplicación sea lenta
  • Cómo desplazar el edittext dentro de la vista de desplazamiento
  • Android drawBitmap (...) el método es lento?
  • ¿Por qué la mayoría de los marcos de la interfaz de usuario se subproceso único?
  • ¿Qué objeto de diseño se utiliza para producir una ventana emergente "burbuja" en una interfaz de usuario de Android? (No Tostada o Diálogo)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.