How to create a closed (round) ListView?

I want to create a custom ListView (or similar) that will behave as a private (circular):

  • scroll down - after the last element has been reached, the first begins (.., n-1, n, 1, 2, ..)
  • scroll up - after the first element has been reached, the last starts (.., 2, 1, n, n-1, ..)

It sounds just conceptual, but there seems to be no easy approach. Can someone point me to the right solution? Thank!

I already got an answer (from Streets Of Boston to google Android developer groups), but that sounds kind of ugly :) -

I did this by creating my own list-adapter (subclasses from BaseAdapter).

I encoded my own adapter list in this way, returned by the getCount () method with the HUUUUGE number.

And if the item 'x' is selected, then this element corresponds to the adapter position = 'adapter.getCount () / 2 + x'

And for my adapter getItem (int position), I look in my array that backs up the adapter and select the item by index: (position-getCount () / 2)% myDataItems.length

You need to make a few more β€œspecials” so that it all works correctly, but you get this idea.

In principle, it is still possible to reach the end or the beginning, but if you set getCount () to about a million or so, it's hard to do :-)

+57
android listview customization circular-buffer
Feb 25 '10 at 9:18
source share
5 answers

My colleague is Joe, and I believe that we have found an easier way to solve the same problem. In our solution, instead of extending the BaseAdapter, we extend the ArrayAdapter.

The code is as follows:

public class CircularArrayAdapter< T > extends ArrayAdapter< T > { 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]; } } 

Thus, a class is created called CircularArrayAdapter, which takes the type of the object T (which can be any) and uses it to create a list of arrays. T is usually a string, although it can be anything.

The constructor is the same as for the ArrayAdapter, but it initializes a constant named middle. This is the middle of the list. No matter how long the MIDDLE array can be used to center the ListView in the middle of the list.

getCount() overrides to return a huge value, as was done above when creating a huge list.

getItem() overrides to return a fake position in the array. Thus, when filling out the list, the list is filled with objects cyclically.

At this point, the CircularArrayAdapter simply replaces the ArrayAdapter in the file that creates the ListView.

To center the ListView, the following line must be inserted into your file, creating the ListView after the ListView object is initialized:

 listViewObject.setSelectionFromTop(nameOfAdapterObject.MIDDLE, 0); 

and using the MIDDLE constant pre-initialized for the list, the view is centered with the top of the list at the top of the screen.

:) ~ Cheers, I hope this solution is useful.

+84
Feb 09 '11 at 0:15
source share

You mentioned a solution that I told other developers to use in the past. In getCount (), just return Integer.MAX_VALUE, it will give you about 2 billion items, which should be enough.

+13
Feb 25 2018-10-25T00
source share

I have, or I think I did it right, based on the answers above. Hope this helps you.

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

And you would like to do this if you want to scroll down the list. Usually we can simply scroll up and the list, and then scroll down.

// see how many elements we would like to scroll through. in this case Integer.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(); 

// see how many pages we have

 int howManySpans = listViewLength / span; 

// see where you want to be when you start listview. you do not need to do things "-3". For my application, this works correctly.

 recipeListView.setSelection((span * (howManySpans / 2)) - 3); 
+8
Nov 05 '10 at 16:06
source share

I could find some good answers for this, one of my friends tried to achieve this with a simple solution. Check out the github project.

+1
Aug 16 2018-12-12T00:
source share

When using LoadersCallbacks, I created the MyCircularCursor class, which wraps a typical cursor like this:

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

decorator class code is here:

 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); } } 
+1
Jan 31 '13 at
source share



All Articles