2010-02-25 9 views
57

que quieren crear un ListView personalizado (o similar), que se comportará como un sistema cerrado (circular) uno:Cómo crear un ListView cerrado (circular)?

  1. el desplazamiento hacia abajo - después de alcanzar el último elemento de la primera comienza (.., N-1, n, 1, 2, ..)
  2. desplazamiento hacia arriba - después de que el primer punto se alcanzó el último comienza (.., 2, 1, n, n-1, ..)

suena simple conceptualmente pero, aparentemente, no hay un enfoque directo para hacer esto. ¿Alguien puede indicarme la solución correcta? ¡Gracias!

ya he recibido una respuesta (de calles de Boston en grupos Android-Desarrolladores de Google), pero suena de alguna manera fea :) -

Hice esto mediante la creación de mi propia lista -adaptador (subclase desde BaseAdapter).

Codifiqué mi propio adaptador de lista en tal forma que su método getCount() devuelve un número HUUUUGE.

Y si el artículo 'X' se selecciona, entonces este artículo corresponde al adaptador posición = 'adapter.getCount()/2 + x'

Y para el método getItem (posición int) de mi adaptador, miro en mi arsenal que respalda el adaptador y buscar el punto del índice: (posición-getCount()/2)% myDataItems.length

Es necesario hacer un poco más 'especial' cosas para hacer todo funciona correctamente, pero ya se entiende.

En principio, es todavía posible llegar al final o al principio de la lista , pero si establece getCount() para alrededor de un millón o más, esto es difícil de hacer :-)

+0

del Sr. Boston es la única opción disponible, si se apega a las clases en la jerarquía 'AdapterView' (por ejemplo,' ListView'). – CommonsWare

+0

No me apegaré a ningún tipo de clases. Menciono ListView solo para dar una idea del comportamiento y aspecto del control, también puede llamarlo "tabla" si lo desea. Algo muy personalizado podría ser un conjunto de celdas que forma una lista, y cuando una de estas celdas sale del área visible, el motor actualizará (desde diferentes hilos, creo) su posición (coordenadas) y contenidos (texto + imágenes) . Pero este proceso de actualización puede afectar la suavidad del desplazamiento. – user281076

+0

¿Dónde debería escribir position = adapter.getcount()/2 + x? – Diffy

Respuesta

13

La solución que mencionas es la que les dije a otros desarrolladores que utilizaran en el pasado. En getCount(), simplemente devuelve Integer.MAX_VALUE, le dará aproximadamente 2 mil millones de elementos, lo cual debería ser suficiente.

+0

Gracias por sus respuestas. Hugh number solution :) – user281076

+0

@Romain Guy: El uso de la solución Hugh Number hará que el rendimiento sea un problema al intentar obtener una gran cantidad de datos. – Surej

+1

@Surej Creo que está intentando sugerir que devolver un "gran número" tendrá un impacto en el rendimiento. No lo hará; [una breve reseña de la fuente] (https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/ListView.java) revela que ListViews no asigna ninguna objetos basados ​​puramente en este número. La única excepción de la que no estoy seguro es usar el modo de diseño 'LAYOUT_FORCE_BOTTOM' mientras se completa de abajo hacia arriba, pero no lo analicé en detalle. –

8

Tengo, o creo que lo he hecho bien, basado en las respuestas anteriores. Espero que esto te ayude.

private static class RecipeListAdapter extends BaseAdapter { 
    private static LayoutInflater mInflater; 
    private Integer[]    mCouponImages; 
    private static ImageView  viewHolder; 
    public RecipeListAdapter(Context c, Integer[] coupomImages) { 
     RecipeListAdapter.mInflater = LayoutInflater.from(c); 
     this.mCouponImages = coupomImages; 
    } 
    @Override 
    public int getCount() { 
     return Integer.MAX_VALUE; 
    } 

    @Override 
    public Object getItem(int position) { 
     // you can do your own tricks here. to let it display the right item in your array. 
     return position % mCouponImages.length; 
    } 

    @Override 
    public long getItemId(int position) { 
     return position; 
     // return position % mCouponImages.length; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 

     if (convertView == null) { 
      convertView = mInflater.inflate(R.layout.coupon_list_item, null); 
      viewHolder = (ImageView) convertView.findViewById(R.id.item_coupon); 
      convertView.setTag(viewHolder); 
     } else { 
      viewHolder = (ImageView) convertView.getTag(); 
     } 

     viewHolder.setImageResource(this.mCouponImages[position %  mCouponImages.length]); 
     return convertView; 
    } 

} 

Y desea hacer esto si desea desplazarse hacia abajo en la lista. Comúnmente podemos simplemente desplazarnos hacia arriba y hacia la lista y luego desplazarnos hacia abajo.

// ver cuántos artículos nos gustaría tener. en este caso, entero.MAX_VALUE

int listViewLength = adapter.getCount(); 

// see how many items a screen can dispaly, I use variable "span" 
    final int span = recipeListView.getLastVisiblePosition() - recipeListView.getFirstVisiblePosition(); 

// ver cuántas páginas tenemos

int howManySpans = listViewLength/span; 

// ver dónde quieres ser cuando comience la vista de lista. no tienes que hacer las cosas "-3". es para que mi aplicación funcione correctamente.

recipeListView.setSelection((span * (howManySpans/2)) - 3); 
82

Mi colega Joe, y creo que hemos encontrado una manera más simple de resolver el mismo problema. En nuestra solución, aunque en lugar de extender BaseAdapter, ampliamos ArrayAdapter.

El código es el barbechos:


public class CircularArrayAdapter extends ArrayAdapter 
{ 

     public static final int HALF_MAX_VALUE = Integer.MAX_VALUE/2; 
     public final int MIDDLE; 
     private T[] objects; 

     public CircularArrayAdapter(Context context, int textViewResourceId, T[] objects) 
     { 
      super(context, textViewResourceId, objects); 
      this.objects = objects; 
      MIDDLE = HALF_MAX_VALUE - HALF_MAX_VALUE % objects.length; 
     } 

     @Override 
     public int getCount() 
     { 
      return Integer.MAX_VALUE; 
     } 

     @Override 
     public T getItem(int position) 
     { 
      return objects[position % objects.length]; 
     } 
} 

Así que esto crea una clase llamada CircularArrayAdapter que toman un tipo de objeto T (que puede ser cualquier cosa) y lo utiliza para crear una lista de arreglo. T es comúnmente una cuerda, aunque puede ser cualquier cosa.

El constructor es el mismo que para ArrayAdapter aunque inicializa una constante llamada middle. Este es el medio de la lista. No importa la longitud de la matriz MIDDLE, se puede usar para centrar ListView en la mitad de la lista.

getCount está anulado para devolver un gran valor como se hizo anteriormente creando una gran lista.

getItem está anulado para devolver la posición falsa en la matriz. Por lo tanto, al completar la lista, la lista se llena con objetos de forma cíclica.

En este punto, CircularArrayAdapter simplemente reemplaza ArrayAdapter en el archivo que crea el ListView.

Para centrar el ListView la línea de vacío sanitario debe insertarse en el archivo de la creación de la ListView después del objeto ListView se ha inicializado:

listViewObject.setSelectionFromTop(nameOfAdapterObject.MIDDLE, 0);

y utilizando la constante MEDIO previamente inicializado para la lista de la vista es centrado con el elemento superior de la lista en la parte superior de la pantalla.

:) ~ Saludos, espero que esta solución sea útil.

+0

Esta debería ser la solución. Esto es increíblemente simple y funciona sin problemas. Gracias – Tom

+0

@Dawson: Si los elementos se actualizarán mientras se llega a la parte superior (es decir, se desplazará de abajo hacia arriba). ¿Después de alcanzar el primer elemento nuevamente se mostrarán los últimos elementos en la parte superior? – Surej

+0

¡Gracias por esto, perfecto! – nebulae

1

Pude ver algunas buenas respuestas para esto, Una de mis friend ha intentado lograr esto a través de una solución simple. Compruebe el proyecto github.

+0

¿Cómo podemos crear una vista de lista circular bidireccional, cuando se desplaza hacia arriba debe mostrar el último elemento. ¿Me puedes dar alguna pista? – Dory

1

Si se utiliza LoadersCallbacks He creado clase MyCircularCursor que envuelve el cursor típica de esta manera:

código de clase
@Override 
public void onLoadFinished(Loader<Cursor> pCursorLoader, Cursor pCursor) { 
     mItemListAdapter.swapCursor(new MyCircularCursor(pCursor)); 
} 

el decorador está aquí: solución

public class MyCircularCursor implements Cursor { 

private Cursor mCursor; 

public MyCircularCursor(Cursor pCursor) { 
    mCursor = pCursor; 
} 

@Override 
public int getCount() { 
    return mCursor.getCount() == 0 ? 0 : Integer.MAX_VALUE; 
} 

@Override 
public int getPosition() { 
    return mCursor.getPosition(); 
} 

@Override 
public boolean move(int pOffset) { 
    return mCursor.move(pOffset); 
} 

@Override 
public boolean moveToPosition(int pPosition) { 
    int position = MathUtils.mod(pPosition, mCursor.getCount()); 
    return mCursor.moveToPosition(position); 
} 

@Override 
public boolean moveToFirst() { 
    return mCursor.moveToFirst(); 
} 

@Override 
public boolean moveToLast() { 
    return mCursor.moveToLast(); 
} 

@Override 
public boolean moveToNext() { 
    if (mCursor.isLast()) { 
     mCursor.moveToFirst(); 
     return true; 
    } else { 
     return mCursor.moveToNext(); 
    } 
} 

@Override 
public boolean moveToPrevious() { 
    if (mCursor.isFirst()) { 
     mCursor.moveToLast(); 
     return true; 
    } else { 
     return mCursor.moveToPrevious(); 
    } 
} 

@Override 
public boolean isFirst() { 
    return false; 
} 

@Override 
public boolean isLast() { 
    return false; 
} 

@Override 
public boolean isBeforeFirst() { 
    return false; 
} 

@Override 
public boolean isAfterLast() { 
    return false; 
} 

@Override 
public int getColumnIndex(String pColumnName) { 
    return mCursor.getColumnIndex(pColumnName); 
} 

@Override 
public int getColumnIndexOrThrow(String pColumnName) throws IllegalArgumentException { 
    return mCursor.getColumnIndexOrThrow(pColumnName); 
} 

@Override 
public String getColumnName(int pColumnIndex) { 
    return mCursor.getColumnName(pColumnIndex); 
} 

@Override 
public String[] getColumnNames() { 
    return mCursor.getColumnNames(); 
} 

@Override 
public int getColumnCount() { 
    return mCursor.getColumnCount(); 
} 

@Override 
public byte[] getBlob(int pColumnIndex) { 
    return mCursor.getBlob(pColumnIndex); 
} 

@Override 
public String getString(int pColumnIndex) { 
    return mCursor.getString(pColumnIndex); 
} 

@Override 
public short getShort(int pColumnIndex) { 
    return mCursor.getShort(pColumnIndex); 
} 

@Override 
public int getInt(int pColumnIndex) { 
    return mCursor.getInt(pColumnIndex); 
} 

@Override 
public long getLong(int pColumnIndex) { 
    return mCursor.getLong(pColumnIndex); 
} 

@Override 
public float getFloat(int pColumnIndex) { 
    return mCursor.getFloat(pColumnIndex); 
} 

@Override 
public double getDouble(int pColumnIndex) { 
    return mCursor.getDouble(pColumnIndex); 
} 

@Override 
public int getType(int pColumnIndex) { 
    return 0; 
} 

@Override 
public boolean isNull(int pColumnIndex) { 
    return mCursor.isNull(pColumnIndex); 
} 

@Override 
public void deactivate() { 
    mCursor.deactivate(); 
} 

@Override 
@Deprecated 
public boolean requery() { 
    return mCursor.requery(); 
} 

@Override 
public void close() { 
    mCursor.close(); 
} 

@Override 
public boolean isClosed() { 
    return mCursor.isClosed(); 
} 

@Override 
public void registerContentObserver(ContentObserver pObserver) { 
    mCursor.registerContentObserver(pObserver); 
} 

@Override 
public void unregisterContentObserver(ContentObserver pObserver) { 
    mCursor.unregisterContentObserver(pObserver); 
} 

@Override 
public void registerDataSetObserver(DataSetObserver pObserver) { 
    mCursor.registerDataSetObserver(pObserver); 
} 

@Override 
public void unregisterDataSetObserver(DataSetObserver pObserver) { 
    mCursor.unregisterDataSetObserver(pObserver); 
} 

@Override 
public void setNotificationUri(ContentResolver pCr, Uri pUri) { 
    mCursor.setNotificationUri(pCr, pUri); 
} 

@Override 
public boolean getWantsAllOnMoveCalls() { 
    return mCursor.getWantsAllOnMoveCalls(); 
} 

@Override 
public Bundle getExtras() { 
    return mCursor.getExtras(); 
} 

@Override 
public Bundle respond(Bundle pExtras) { 
    return mCursor.respond(pExtras); 
} 

@Override 
public void copyStringToBuffer(int pColumnIndex, CharArrayBuffer pBuffer) { 
    mCursor.copyStringToBuffer(pColumnIndex, pBuffer); 
} 
} 
Cuestiones relacionadas