Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Barra de progreso de giro en cada elemento de vista de lista

He estado rascándome la cabeza sobre esto desde hace mucho tiempo y busqué una respuesta sin ninguna suerte! Parece ser trivial, pero por lo que sé, no lo es.

Utilizo una vista de lista en mi aplicación de Android donde cada elemento (vista) muestra un ProgressBar giratorio antes de que el contenido se cargue y se muestre (el contenido se recupera a través de llamadas http y json, por lo que puede tardar un tiempo en procesarse). El problema es que las barras de progreso giratorio giran independientemente entre sí, creando así el efecto de un caos giratorio en lugar de una fila sincronizada de marcadores de carga de buen aspecto.

  • ¿Por qué la clase singleton sobrevive a la actividad?
  • Borra toda la pila de historiales e inicia una nueva actividad en Android
  • Error de ejecución de la tarea ': app: compileDebugNdk'
  • MapView dentro de ScrollView?
  • NDK que compila varias bibliotecas
  • Cómo cambiar el color predeterminado del diálogo DatePicker y TimePicker en Android?
  • He intentado todo lo que podría llegar a … no reciclar el ProgressBar en getView () … sólo tienen una instancia de la misma ProgressBar … restablecer el ProgressBars android: el progreso siempre que los elementos de la lista se hace visible (a través de onScroll () En la actividad) … etc, pero ya que comienzan a girar en el tiempo de creación (cuando getView se llama en el adaptador) que nunca tendrá la misma sincronización de ciclo.

    Introduzca aquí la descripción de la imagen

    ¡Cualquier sugerencia es bienvenida!

  • Sw600dp cuantificador no funciona en Galaxy Tab
  • Api de YouTube: No está conectado. Llame a connect () y espere a que onConnected () se llame
  • Google Analytics en Android da la duración de la sesión de la media: 00:00:00
  • Obtener el nombre de la actividad dinámicamente - android
  • ¿Actualización de esquema GreenDAO y migración de datos?
  • Error (1, -2147483648) en Android
  • 6 Solutions collect form web for “Barra de progreso de giro en cada elemento de vista de lista”

    EDIT: Ahora funciona perfectamente! – la llamada de escucha de animación insertada setStartOffset () vuelve a 0 después de la primera repetición para que no mantenga "saltando" al azar.


    Encontré una solución de trabajo para este problema, que funciona sincronizando la animación con el sistema actual en milisegundos. Es un poco un hack, ya que utiliza la reflexión para obtener el campo mAnimation en ProgressBar . Dicho esto, este campo se ha mantenido en su lugar en las fuentes de Android desde que fue creado (funciona hasta 4.2).

    Cree la clase android.widget.SyncedProgressBar y utilícela en lugar de ProgressBar en los archivos .xml. Esencialmente hace que la animación comience al principio de la duración de la animación. También puede jugar con setDuration(500) para verificar que funciona (la rueda de progreso girará muy rápido). ¡Espero que esto ayude!

     package android.widget; import android.annotation.SuppressLint; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import java.lang.reflect.Field; /** * @author Oleg Vaskevich * */ public class SyncedProgressBar extends ProgressBar { public SyncedProgressBar(Context context) { super(context); modifyAnimation(); } public SyncedProgressBar(Context context, AttributeSet attrs) { super(context, attrs); modifyAnimation(); } public SyncedProgressBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); modifyAnimation(); } @Override public void setVisibility(int v) { super.setVisibility(v); modifyAnimation(); } @SuppressLint("NewApi") @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); modifyAnimation(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); modifyAnimation(); } @Override public synchronized void setIndeterminate(boolean indeterminate) { super.setIndeterminate(indeterminate); modifyAnimation(); } public void modifyAnimation() { Field mAnim; try { mAnim = ProgressBar.class.getDeclaredField("mAnimation"); mAnim.setAccessible(true); AlphaAnimation anim = (AlphaAnimation) mAnim.get(this); if (anim == null) return; // set offset to that animations start at same time long duration = anim.getDuration(); long timeOffset = System.currentTimeMillis() % duration; anim.setDuration(duration); anim.setStartOffset(-timeOffset); anim.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { animation.setStartOffset(0); } @Override public void onAnimationEnd(Animation animation) { } }); } catch (Exception e) { Log.d("SPB", "that didn't work out...", e); return; } postInvalidate(); } } 

    Así es como hacer que funcione. Utilice sólo un AnimationDrawable, multiplique la devolución de llamada. ProgressBar realmente no agrega nada, es posible que también se adhieran a View. Hacer una subclase de View que omite la gestión Drawable.

     public class Whirly extends View { Drawable image = null; public Whirly(Context context, AttributeSet attr) { super(context, attr); } @Override public void draw(Canvas canvas) { if (image!=null) image.draw(canvas); } public void setImageDrawable(Drawable image) { this.image = image; invalidate(); } } 

    A continuación, haga que su actividad de seguimiento de todos los remolinos de alguna manera.

     public class Demo extends Activity implements Drawable.Callback { private Handler h; private AnimationDrawable a; private Whirly w0; private Whirly w1; private Whirly w2; private Whirly w3; public void onCreate(Bundle bundle) { ... h = new Handler(); a = (AnimationDrawable) getResources().getDrawable(R.drawable.mywhirly); int width = a.getIntrinsicWidth(); int height = a.getIntrinsicHeight(); a.setBounds(0, 0, width, height); w0 = (Whirly) findViewById(R.id.whirly0); w1 = (Whirly) findViewById(R.id.whirly1); w2 = (Whirly) findViewById(R.id.whirly2); w3 = (Whirly) findViewById(R.id.whirly3); w0.setImageDrawable(a); w1.setImageDrawable(a); w2.setImageDrawable(a); w3.setImageDrawable(a); a.setCallback(this); a.start(); } public void invalidateDrawable (Drawable who) { w0.invalidate(); w1.invalidate(); w2.invalidate(); w3.invalidate(); } public void scheduleDrawable (Drawable who, Runnable what, long when) { h.postAtTime(what, who, when); } public void unscheduleDrawable (Drawable who, Runnable what) { h.removeCallbacks(what, who); } } 

    En su adaptador getView () deshabilitar su progressViwe, y luego para cada ProgressView

     handler.postAtTime(new Runnable(){ public void run(){ progressView.setEnabled(true); }}, someTimeInTheFuture ); 

    Lo que esto hará es activar todas sus vistas de progreso al mismo tiempo. Esto podría funcionar, no he probado. Si esto no funciona, es posible que desee añadir el progreso de forma dinámica (no incluido en el diseño, pero agregue a través de addView ()). Pero hacerlo en el runnable, la clave aquí es para que todos se agregan al mismo tiempo.

    Cavando a través del código fuente veo que la imagen giratoria es un dibujable que está girando debido a una Animation privada. No hay manera de obtener la vista o la animación, descartando así cualquier idea que tenía de reutilizar una animación en todas las vistas. Yo diría que su única alternativa es lo que sugería Jugéernaut, aunque no es la más bonita de las soluciones.

    No estoy seguro de que esto sea posible dado que cada fila de su ListView se recicla cuando se mueve fuera de la pantalla. Cuando aparezca una nueva fila en la pantalla, las vistas de ProgressBar tendrán que volver a sincronizarse entre sí. Mantener todas las filas en sincronía va a ser un gran PITA.

    ¿Ha considerado la carga de todos los datos de la lista en una solicitud y el almacenamiento en caché de esos datos en el almacenamiento local? Sería mucho más eficiente y daría lugar a una mejor experiencia del usuario. No es muy útil tener un ListView que se carga inmediatamente con filas vacías. Prefiero esperar a que la lista se llene por completo.

    1> Crear diseño para la fila de la lista

     <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:padding="10dip" > <TextView android:id="@+id/word_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:text="Word 1" /> <ProgressBar android:id="@+id/row_progress" style="@style/Widget.Sherlock.Light.ProgressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:indeterminate="true" /> <ImageView android:id="@+id/speaker" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:src="@drawable/speaker_icon" android:visibility="gone"/> </RelativeLayout> 

    2> Entonces en el método getView

     if(word.getIsWordSynchedLocally() == 1){ convertView.findViewById(R.id.row_progress).setVisibility(View.GONE); convertView.findViewById(R.id.speaker).setVisibility(View.VISIBLE); }else{ convertView.findViewById(R.id.row_progress).setVisibility(View.VISIBLE); convertView.findViewById(R.id.speaker).setVisibility(View.GONE); } 
    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.