Wie erstelle ich eine geschlossene (kreisförmige) ListView?

Lesezeit: 9 Minuten

Wie erstelle ich eine geschlossene kreisformige ListView
Benutzer281076

Ich möchte eine benutzerdefinierte ListView (oder ähnliches) erstellen, die sich wie eine geschlossene (kreisförmige) verhält:

  1. nach unten scrollen – nachdem das letzte Element erreicht wurde, beginnt das erste (.., n-1, n, 1, 2, ..)
  2. nach oben scrollen – nachdem das erste Element erreicht wurde, beginnt das letzte (.., 2, 1, n, n-1, ..)

Es klingt konzeptionell einfach, aber anscheinend gibt es dafür keinen direkten Ansatz. Kann mir jemand die richtige Lösung zeigen? Danke !

Ich habe bereits eine Antwort erhalten (von Streets Of Boston auf Android-Developers Google Groups), aber es klingt irgendwie hässlich 🙂 –

Ich habe dies getan, indem ich meinen eigenen Listenadapter erstellt habe (von BaseAdapter abgeleitet).

Ich habe meinen eigenen Listenadapter so codiert, dass seine Methode getCount() eine RIESIGE Zahl zurückliefert.

Und wenn das Element „x“ ausgewählt ist, entspricht dieses Element der Adapterposition = „adapter.getCount()/2+x“.

Und für die Methode getItem (int position) meines Adapters schaue ich in mein Array, das den Adapter sichert, und hole das Element auf dem Index: (position-getCount()/2) % myDataItems.length

Sie müssen noch einige “spezielle” Dinge tun, damit alles richtig funktioniert, aber Sie verstehen die Idee.

Im Prinzip ist es immer noch möglich, das Ende oder den Anfang der Liste zu erreichen, aber wenn Sie getCount() auf etwa eine Million oder so setzen, ist dies schwierig 🙂

  • Die Lösung von Herrn Boston ist die einzige verfügbare Option, wenn Sie sich an den Unterricht halten AdapterView Hierarchie (z. B. ListView).

    – CommonsWare

    25. Februar 2010 um 13:01 Uhr

  • Ich halte mich nicht an irgendeinen Unterricht. Ich erwähne ListView nur, um eine Vorstellung vom Verhalten und Aussehen des Steuerelements zu geben, Sie können es auch “Tabelle” nennen, wenn Sie möchten. Etwas sehr Benutzerdefiniertes könnte eine Reihe von Zellen sein, die eine Liste bilden, und wenn eine dieser Zellen den sichtbaren Bereich verlässt, aktualisiert die Engine (von einem anderen Thread, glaube ich) ihre Position (Koordinaten) und ihren Inhalt (Text + Bilder). . Dieser Aktualisierungsvorgang kann jedoch das reibungslose Scrollen beeinträchtigen.

    – Benutzer281076

    25. Februar 2010 um 14:49 Uhr


  • Wo soll ich position=adapter.getcount()/2+x schreiben?

    – Schwierig

    26. September 2014 um 11:25 Uhr

Wie erstelle ich eine geschlossene kreisformige ListView
Dawson

Mein Kollege Joe und ich glauben, dass wir einen einfacheren Weg gefunden haben, dasselbe Problem zu lösen. In unserer Lösung erweitern wir jedoch, anstatt BaseAdapter zu erweitern, ArrayAdapter.

Der Code lautet wie folgt:

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

Dies erstellt also eine Klasse namens CircularArrayAdapter, die einen Objekttyp T (der alles sein kann) nimmt und ihn zum Erstellen einer Array-Liste verwendet. T ist normalerweise eine Zeichenfolge, kann aber alles sein.

Der Konstruktor ist derselbe wie für ArrayAdapter, initialisiert jedoch eine Konstante namens middle. Dies ist die Mitte der Liste. Unabhängig von der Länge des Arrays MIDDLE kann die ListView in der Mitte der Liste zentriert werden.

getCount() Dies überschreibt, um einen riesigen Wert zurückzugeben, wie es oben beim Erstellen einer riesigen Liste getan wurde.

getItem() wird überschrieben, um die gefälschte Position auf dem Array zurückzugeben. Somit wird beim Füllen der Liste die Liste in einer Schleifenweise mit Objekten gefüllt.

An diesem Punkt ersetzt CircularArrayAdapter einfach ArrayAdapter in der Datei, die die ListView erstellt.

Um die ListView zu zentrieren, muss die folgende Zeile in Ihre Datei eingefügt werden, die die ListView erstellt, nachdem das ListView-Objekt initialisiert wurde:

listViewObject.setSelectionFromTop(nameOfAdapterObject.MIDDLE, 0);

und unter Verwendung der zuvor für die Liste initialisierten MIDDLE-Konstante wird die Ansicht mit dem obersten Element der Liste am oberen Rand des Bildschirms zentriert.

🙂 ~ Prost, ich hoffe, diese Lösung ist nützlich.

  • Das sollte die Lösung sein. Das ist verblüffend einfach und funktioniert einwandfrei. Danke

    – Tom

    1. Juni 2011 um 0:27 Uhr

  • @Dawson: Ob die Elemente aktualisiert werden, während sie ganz oben sind (dh) von unten nach oben scrollen. Nach dem erneuten Erreichen des ersten Elements werden die letzten Elemente oben angezeigt?

    – Surej

    24. April 2012 um 6:19 Uhr

  • Ich bin gerade auf diese Lösung gestoßen, und ehrlich gesagt ist es erstaunlich, wie einfach der Code ist. Hut ab!

    – Sreedevi J

    29. August 2013 um 6:52 Uhr

  • @prodaea Sie verwalten sich selbst. Wenn ich 19 Elemente im Array habe und zum Ende der Liste scrolle, also mein Index 0 ist, ist alles in Ordnung. Wenn ich ein zusätzliches Element nach unten scrolle und mein Index somit -1 ist, wird -1 % 19 in Java zu 18 ausgewertet, was das letzte Element in meiner Liste ist. In einer kreisförmigen Liste ist das letzte Element logisch vor dem ersten Element, und damit sind wir in Ordnung. In Anbetracht dessen sollte MIDDLE auf 0 gesetzt werden, was es zum Mittelpunkt zwischen Integer.MIN_VALUE und Integer.MAX_VALUE macht. Ich bin froh, dass Sie dies angesprochen haben, weil ich diesen Fall nicht berücksichtigt hatte.

    – Dawson

    31. Oktober 2013 um 14:43 Uhr

  • Ich denke nicht, dass es eine gute Idee ist. Die Verwendung des Adapters besteht darin, dass die Elemente nur bei Bedarf im Speicher erstellt werden, und hier initialisieren Sie den Adapter mit der gesamten Liste der Elemente. Dann ist es kein Adapter, oder? Es ist nur ein Manager, der die Daten bei Bedarf weitergibt.

    – Viswanath Lekshmanan

    24. Dezember 2013 um 5:36 Uhr

Die Lösung, die Sie erwähnen, ist die, die ich anderen Entwicklern in der Vergangenheit empfohlen habe. Geben Sie in getCount() einfach Integer.MAX_VALUE zurück, Sie erhalten ungefähr 2 Milliarden Elemente, was ausreichen sollte.

  • Danke für deine Antworten. Lösung für große Zahlen 🙂

    – Benutzer281076

    26. Februar 2010 um 13:54 Uhr

  • @Romain Guy: Die Verwendung der Hugh Number-Lösung führt zu Leistungsproblemen beim Versuch, eine große Anzahl von Daten zu erhalten.

    – Surej

    24. April 2012 um 11:57 Uhr

  • @Surej Ich glaube, Sie versuchen vorzuschlagen, dass die Rückgabe einer “großen Zahl” die Leistung beeinträchtigt. Es wird nicht; eine kurze Quellenangabe zeigt, dass ListViews keine Objekte nur basierend auf dieser Zahl zuweisen. Die einzige Ausnahme, bei der ich mir nicht sicher bin, ist die Verwendung des Layoutmodus LAYOUT_FORCE_BOTTOM da es von unten nach oben befüllt wird, aber ich habe es mir nicht im Detail angesehen.

    – Paul Lammertsma

    7. April 2013 um 15:29 Uhr

  • @PaulLammertsma Das Erstellen eines Layouts von unten wirkt sich auch nicht auf die Leistung aus.

    – Romain Guy

    8. April 2013 um 17:05 Uhr

  • @RomainGuy seltsamer Fehler- Integer.MAX_VALUE nicht funktionieren (getView nicht aufgerufen) aber Integer.MAX_VALUE - 2 funktionieren wie erwartet. eine Ahnung warum?

    – sie

    13. Oktober 2014 um 13:27 Uhr

1646223191 292 Wie erstelle ich eine geschlossene kreisformige ListView
Harry

Ich habe, oder ich denke, ich habe es richtig gemacht, basierend auf den obigen Antworten. Ich hoffe, das wird Ihnen helfen.

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

}

Und Sie möchten dies tun, wenn Sie in der Liste nach unten scrollen möchten. Normalerweise können wir einfach nach oben scrollen und dann nach unten scrollen.

// sehen, wie viele Artikel wir scrollen möchten. in diesem Fall 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();

// sehen, wie viele Seiten wir haben

int howManySpans = listViewLength / span;

// Sehen Sie, wo Sie sein möchten, wenn Sie die Listenansicht starten. Sie müssen das “-3”-Zeug nicht machen. Es ist für meine App, richtig zu funktionieren.

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

Wie erstelle ich eine geschlossene kreisformige ListView
Wesley

Ich konnte einige gute Antworten dafür sehen. Einer meiner Freunde hat versucht, dies über eine einfache Lösung zu erreichen. Überprüf den github Projekt.

1646223193 0 Wie erstelle ich eine geschlossene kreisformige ListView
ViliusK

Wenn ich LoadersCallbacks verwende, habe ich die Klasse MyCircularCursor erstellt, die den typischen Cursor wie folgt umschließt:

@Override
public void onLoadFinished(Loader<Cursor> pCursorLoader, Cursor pCursor) {
        mItemListAdapter.swapCursor(new MyCircularCursor(pCursor));
}

Der Dekorateur-Klassencode ist hier:

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

911980cookie-checkWie erstelle ich eine geschlossene (kreisförmige) ListView?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy