How to create a closed (circular) ListView?

user281076 picture user281076 · Feb 25, 2010 · Viewed 26.5k times · Source

I want to create a customized ListView (or similar) which will behave like a closed (circular) one:

  1. scrolling down - after the last item was reached the first begins (.., n-1, n, 1, 2, ..)
  2. scrolling upward - after the first item was reached the last begins (.., 2, 1, n, n-1, ..)

It sounds simple conceptually but, apparently, there is no straightforward approach to do this. Can anyone point me to the right solution ? Thank you !

I have already received an answer (from Streets Of Boston on Android-Developers google groups), but it sounds somehow ugly :) -

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

I coded my own list-adapter in such a way that its getCount() method returns a HUUUUGE number.

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

And for my adapter's method getItem(int position), i look in my array that backs up the adapter and fetch the item on index: (position-getCount()/2) % myDataItems.length

You need to do some more 'special' stuff to make it all work correctly, but you get the idea.

In principle, it is still possible to reach the end or the beginning of the list, but if you set getCount() to around a million or so, this is hard to do :-)

Answer

Dawson picture Dawson · Feb 9, 2011

My colleague Joe, and I believe we have found a simpler way to solve the same problem. In our solution though instead of extending BaseAdapter we extend 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];
        }
 }

So this creates a class called CircularArrayAdapter which take an object type T (which may be anything) and uses it to create an array list. T is commonly a string though may be anything.

The constructor is the same as is for ArrayAdapter though initializes a constant called middle. This is the middle of the list. No matter what the length of the array MIDDLE can be used to center the ListView in the mid of the list.

getCount() is overrides to return a huge value as is done above creating a huge list.

getItem() is overrides to return the fake position on the array. Thus when filling the list the list is filled with objects in a looping manner.

At this point CircularArrayAdapter simply replaces ArrayAdapter in the file creating the ListView.

To centre the ListView the fallowing line must be inserted in your file creating the ListView after the ListView object has been initialised:

listViewObject.setSelectionFromTop(nameOfAdapterObject.MIDDLE, 0);

and using the MIDDLE constant previously initialized for the list the view is centered with the top item of the list at the top of the screen.

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