web-dev-qa-db-ja.com

閉じた(円形の)リストビューを作成する方法は?

閉じた(円形)のように動作するカスタマイズされたListView(または同様の)を作成したい:

  1. スクロールダウン-最後のアイテムに到達した後、最初のアイテムが開始されます(..、n-1、n、1、2、..)
  2. 上にスクロール-最初の項目に到達した後、最後の項目が始まります(..、2、1、n、n-1、..)

概念的には単純に聞こえますが、明らかに、これを行うための直接的なアプローチはありません。誰でも私に正しい解決策を教えてもらえますか?ありがとうございました !

私はすでに回答を受け取りました(Android-DevelopersのGoogleグループのStreets Of Bostonから)、それは何となくいように聞こえます:)-

独自のリストアダプター(BaseAdapterのサブクラス)を作成して、これを行いました。

GetCount()メソッドがHUUUUGE番号を返すように、独自のリストアダプターをコーディングしました。

また、アイテム「x」が選択されている場合、このアイテムはアダプター位置=「adapter.getCount()/ 2 + x」に対応します。

そして、アダプターのメソッドgetItem(int position)については、アダプターをバックアップする配列を調べて、インデックス上のアイテムをフェッチします:(position-getCount()/ 2)%myDataItems.length

すべてを正しく機能させるには、さらに「特別な」作業を行う必要がありますが、アイデアは得られます。

原則として、リストの最後または最初に到達することはまだ可能ですが、getCount()を約100万程度に設定すると、これを行うのは困難です:-)

57
user281076

同僚のジョー、そして同じ問題を解決するためのより簡単な方法を見つけたと思います。ただし、ソリューションでは、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];
        }
 }
_

したがって、これにより、オブジェクト型T(任意のタイプ)を取得し、それを使用して配列リストを作成するCircularArrayAdapterというクラスが作成されます。 Tは一般に文字列ですが、何でもかまいません。

コンストラクターはArrayAdapterの場合と同じですが、middleという定数を初期化します。これはリストの中央です。配列MIDDLEの長さに関係なく、ListViewをリストの中央に配置できます。

getCount()は、上記の巨大なリストの作成と同様に、巨大な値を返すオーバーライドです。

getItem()は、配列上の偽の位置を返すためのオーバーライドです。したがって、リストを埋めると、リストはループ形式でオブジェクトで埋められます。

この時点で、CircularArrayAdapterはListViewを作成するファイル内のArrayAdapterを単に置き換えます。

ListViewを中央に配置するには、ListViewオブジェクトが初期化された後に、休憩線をファイルに挿入してListViewを作成する必要があります。

_listViewObject.setSelectionFromTop(nameOfAdapterObject.MIDDLE, 0);
_

リストに対して以前に初期化されたMIDDLE定数を使用すると、画面の上部にあるリストの一番上のアイテムを中心にビューが中央に配置されます。

:)〜乾杯、この解決策が役立つことを願っています。

84
Dawson

あなたが言及する解決策は、私が他の開発者に過去に使用するように言ったものです。 getCount()でInteger.MAX_VALUEを返すだけで、約20億のアイテムが得られますが、これで十分です。

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

これに対するいくつかの良い答えを見ることができました。私の friend の1つは、簡単な解決策でこれを達成しようとしました。 github プロジェクトを確認してください。

1
Wesley