it-swarm.com.ru

Как создать закрытый (круговой) ListView?

Я хочу создать собственный ListView (или аналогичный), который будет вести себя как закрытый (круговой):

  1. прокрутка вниз - после того, как последний элемент был достигнут, начинается первый (.., n-1, n, 1, 2, ..)
  2. прокрутка вверх - после достижения первого элемента начинается последний (.., 2, 1, n, n-1, ..)

Концептуально это звучит просто, но, по-видимому, не существует прямого подхода к этому. Кто-нибудь может указать мне правильное решение? Спасибо !

Я уже получил ответ (от Streets Of Boston на Google-разработчиках Android-групп), но это звучит как-то некрасиво :) -

Я сделал это, создав свой собственный список-адаптер (подкласс из BaseAdapter).

Я кодировал свой собственный список-адаптер таким образом, чтобы его метод getCount () возвращал число HUUUUGE.

И если выбран элемент 'x', то этот элемент соответствует позиции адаптера = 'adapter.getCount ()/2 + x'

И для метода моего адаптера getItem (int position) я смотрю в своем массиве, который создает резервную копию адаптера, и извлекаю элемент по индексу: (position-getCount ()/2)% myDataItems.length

Вам нужно сделать еще несколько "специальных" вещей, чтобы все это работало правильно, но вы поняли идею.

В принципе, все еще возможно достичь конца или начала списка, но если вы установите для getCount () около миллиона или около того, это трудно сделать :-)

57
user281076

Мой коллега Джо, и я считаю, что мы нашли более простой способ решить ту же проблему. В нашем решении вместо расширения BaseAdapter мы расширяем ArrayAdapter.

Код как пара:


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

Таким образом, создается класс с именем CircularArrayAdapter, который принимает тип объекта T (который может быть любым) и использует его для создания списка массивов. T обычно является строкой, хотя может быть чем угодно.

Конструктор такой же, как и для ArrayAdapter, но инициализирует константу с именем middle. Это середина списка. Независимо от того, какую длину массива MIDDLE можно использовать для центрирования ListView в середине списка.

getCount переопределяется, чтобы вернуть огромное значение, как это было сделано выше при создании огромного списка.

getItem переопределяется, чтобы вернуть поддельную позицию в массиве. Таким образом, при заполнении списка список заполняется объектами циклично.

На этом этапе CircularArrayAdapter просто заменяет ArrayAdapter в файле, создающем ListView.

Чтобы центрировать ListView, в файл необходимо вставить следующую строку, создающую ListView после инициализации объекта ListView:

listViewObject.setSelectionFromTop(nameOfAdapterObject.MIDDLE, 0);

и используя константу MIDDLE, предварительно инициализированную для списка, представление центрируется с верхним элементом списка в верхней части экрана.

:) ~ Cheers, я надеюсь, что это решение полезно.

84
Dawson

Решение, которое вы упоминаете, - это то, которое я сказал другим разработчикам использовать в прошлом. В getCount () просто верните Integer.MAX_VALUE, он даст вам около 2 миллиардов элементов, чего должно быть достаточно.

13
Romain Guy

Я сделал, или я думаю, что я сделал это правильно, основываясь на ответах выше. Надеюсь, что это поможет вам.

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);
8
Harry

При использовании 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);
}
}
1
ViliusK

Я мог бы найти некоторые хорошие ответы на это, Один из моих друг пытался достичь этого с помощью простого решения. Проверьте проект github .

1
Wesley