如何创build一个封闭的(循环)ListView?
我想要创build一个自定义的ListView(或类似的),它将performance得像一个封闭的(圆形的):
- 向下滚动 – 在最后一个项目到达后,第一个开始(..,n-1,n,1,2,..)
- 向上滚动 – 在第一个项目到达后,最后一个开始(..,2,1,n,n-1,..)
这在概念上听起来很简单,但显然,没有直接的方法来做到这一点。 任何人都可以指出我正确的解决scheme? 谢谢 !
我已经收到了一个答案(来自波士顿街道上的Android开发人员谷歌组),但它听起来不知何故难看:) –
我通过创build我自己的列表适配器(从BaseAdapter分类)做到了这一点。
我编写我自己的列表适配器,使得它的getCount()方法返回一个HUUUUGE数字。
如果项目'x'被选中,则这个项目对应于适配器位置='adapter.getCount()/ 2 + x'
对于我的适配器的方法getItem(int position),我查看我的数组,备份适配器并获取索引上的项目:(position-getCount()/ 2)%myDataItems.length
你需要做一些更“特殊”的东西,使其一切工作正常,但你明白了。
原则上,它仍然可以达到列表的结尾或开始,但是如果将getCount()设置为大约一百万左右,这很难做到:-)
我的同事乔,我相信我们已经find了一个更简单的方法来解决同样的问题。 在我们的解决scheme中,我们扩展了ArrayAdapter,而不是扩展BaseAdapter。
代码如下:
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]; } }
所以这创build了一个名为CircularArrayAdapter的类,它接受一个对象typesT(可以是任何东西)并用它来创build一个数组列表。 T通常是一个string,尽pipe可能是任何东西。
虽然初始化一个叫做middle的常量,但构造函数与ArrayAdapter的相同。 这是名单的中间。 不pipe数组MIDDLE的长度是什么,都可以用来将ListView居中放在列表中间。
getCount被覆盖以返回一个巨大的值,就像上面创build一个巨大的列表一样。
getItem被覆盖以返回数组上的假位置。 因此,填充列表时,列表以循环方式填充对象。
此时,CircularArrayAdapter简单地replace创buildListView的文件中的ArrayAdapter。
要将ListView居中,必须在ListView对象初始化后,将下面的行插入到创buildListView的文件中:
listViewObject.setSelectionFromTop(nameOfAdapterObject.MIDDLE, 0);
并使用之前为列表初始化的MIDDLE常量,视图以屏幕顶部列表顶部的项目为中心。
:)〜干杯,我希望这个解决scheme很有用。
你提到的解决scheme是我曾经告诉其他开发人员使用的解决scheme。 在getCount()中,只需返回Integer.MAX_VALUE,它会给你大约20亿个项目,这应该足够了。
根据上面的答案,我有,或者我认为我做得对。 希望这会帮助你。
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; } }
如果你想向下滚动列表,你想这样做。 通常我们可以向上滚动并列出,然后向下滚动。
//看看我们想要打几个项目 在这种情况下,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();
//看看我们有多less页
int howManySpans = listViewLength / span;
//开始列表视图时,看看你想要在哪里。 你不必做“-3”的东西。 这是我的应用程序正确工作。
recipeListView.setSelection((span * (howManySpans / 2)) - 3);
我可以看到一些很好的答案,我的一个朋友试图通过一个简单的解决scheme来实现这一点。 检查github项目。
如果使用LoadersCallbacks,我创build了MyCircularCursor类,它包装了典型的光标,如下所示:
@Override public void onLoadFinished(Loader<Cursor> pCursorLoader, Cursor pCursor) { mItemListAdapter.swapCursor(new MyCircularCursor(pCursor)); }
装饰类的代码在这里:
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); } }