如何创建一个封闭(循环)的ListView?

问题描述 投票:0回答:5

我想创建一个自定义的 ListView(或类似的),其行为就像一个封闭的(圆形)列表:

  1. 向下滚动 - 到达最后一项后,第一项开始 (.., n-1, n, 1, 2, ..)
  2. 向上滚动 - 到达第一项后,最后一项开始 (.., 2, 1, n, n-1, ..)

这在概念上听起来很简单,但显然没有直接的方法可以做到这一点。 谁能指出我正确的解决方案? 谢谢!

我已经收到了答案(来自 Android-Developers google groups 上的 Streets Of Boston),但听起来有些难看:) -

我通过创建自己的 列表适配器(子类自 底座适配器)。

我用这样的方式编写了自己的列表适配器 getCount() 方法返回的方式 一个巨大的数字。

如果选择了“x”项,则此 项目对应适配器 位置='adapter.getCount()/2+x'

对于我的适配器的方法 getItem(intposition),我查看我的 备份适配器的阵列和 获取索引上的项目: (position-getCount()/2) % myDataItems.length

你需要做一些更“特别”的事情 使一切正常工作的东西, 但你明白了。

原则上还是可以的 到达结束或开始 列表,但如果将 getCount() 设置为 大约一百万左右,这很难 要做的事:-)

android listview customization
5个回答
84
投票

我的同事乔和我相信我们已经找到了一种更简单的方法来解决同样的问题。在我们的解决方案中,我们不是扩展 BaseAdapter,而是扩展 ArrayAdapter。

代码如下:

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

因此,这创建了一个名为 CircularArrayAdapter 的类,它采用对象类型 T(可以是任何类型)并使用它来创建数组列表。 T 通常是一个字符串,但也可以是任何东西。

构造函数与 ArrayAdapter 的构造函数相同,但初始化了一个名为 middle 的常量。这是列表的中间部分。无论数组的长度是多少,MIDDLE 都可以用来将 ListView 置于列表的中间。

getCount()
被覆盖以返回一个巨大的值,就像上面创建一个巨大的列表所做的那样。

getItem()
被覆盖以返回数组上的假位置。因此,在填充列表时,列表会以循环方式填充对象。

此时,CircularArrayAdapter 只是替换了创建 ListView 的文件中的 ArrayAdapter。

要使 ListView 居中,必须在初始化 ListView 对象后将以下行插入到创建 ListView 的文件中:

listViewObject.setSelectionFromTop(nameOfAdapterObject.MIDDLE, 0);

并使用之前为列表初始化的 MIDDLE 常量,视图以屏幕顶部列表的顶部项目为中心。

:)〜干杯,我希望这个解决方案有用。


13
投票

您提到的解决方案是我过去告诉其他开发人员使用的解决方案。在 getCount() 中,只需返回 Integer.MAX_VALUE,它会给你大约 20 亿个项目,这应该足够了。


9
投票

根据上面的答案,我已经,或者我认为我做得对了。 希望对你有帮助。

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();

// 看看我们有多少页

int howManySpans = listViewLength / span;

// 查看启动列表视图时您想要在哪里。你不必做“-3”的事情。 这是为了我的应用程序正常工作。

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

1
投票

我可以看到一些很好的答案,我的一位朋友尝试通过一个简单的解决方案来实现这一目标。检查 github 项目。


1
投票

如果使用 LoadersCallbacks,我创建了 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);
}
}
© www.soinside.com 2019 - 2024. All rights reserved.