Korrigieren Sie die Animation eines Circular ViewPagers

Tor

Erstellen Sie einen Circular ViewPager.

Mit dem ersten Element können Sie einen Peak zum letzten Element setzen und dorthin streichen und umgekehrt. Sie sollten für immer in beide Richtungen streichen können.

Dies wurde bereits zuvor durchgeführt, aber diese Fragen funktionieren für meine Implementierung nicht. Hier sind einige als Referenz:

wie erstelle ich einen kreisrunden viewpager?ViewPager als kreisförmige Warteschlange / Umhüllunghttps://github.com/antonyt/InfiniteViewPager

Wie ich versuchte, das Problem zu lösen

Als Beispiel verwenden wir ein Array der Größe 7. Die Elemente sind wie folgt:

[0][1][2][3][4][5][6]

Wenn Sie sich bei Element 0 befinden, können Sie mit ViewPagern nicht nach links wischen! Wie schrecklich :(. Um das zu umgehen, habe ich 1 Element an der Vorderseite und am Ende hinzugefügt.

   [0][1][2][3][4][5][6]      // Original
[0][1][2][3][4][5][6][7][8]   // New mapping

Wenn der ViewPageAdapter nach (instantiateItem ()) Element 0 fragt, geben wir Element 7 zurück. Wenn der ViewPageAdapter nach Element 8 fragt, geben wir Element 1 zurück.

Ebenso setzen wir im OnPageChangeListener im ViewPager, wenn onPageSelected mit 0 aufgerufen wird, CurrentItem (7) und wenn es mit 8 aufgerufen wird, setCurrentItem (1).

Das funktioniert.

Das Problem

Wenn Sie von 1 nach 0 nach links wischen und "CurrentItem" (7) einstellen, wird die Animation um 6 Vollbildschirme nach rechts animiert. Dies gibt nicht das Erscheinungsbild eines kreisförmigen ViewPagers, sondern das Erscheinungsbild, das zum letzten Element in die entgegengesetzte Richtung rauscht, die der Benutzer mit seiner Wischbewegung angefordert hat!

Das ist sehr, sehr beunruhigend.

Wie ich versucht habe, das zu lösen

Meine erste Neigung war, sanfte (dh alle) Animationen auszuschalten. Es ist ein bisschen besser, aber jetzt ist es abgehackt, wenn Sie vom letzten Element zum ersten und umgekehrt wechseln.

Ich habe dann meinen eigenen Scroller gemacht.

http://developer.android.com/reference/android/widget/Scroller.html

Was ich fand, war, dass es immer 1 Aufruf von startScroll () gibt, wenn man sich zwischen Elementen bewegt,außer wenn ich von 1 auf 7 und von 7 auf 1 gehe.

Der erste Aufruf ist die richtige Animation in Richtung und Höhe.

Der zweite Aufruf ist die Animation, die alles um mehrere Seiten nach rechts verschiebt.

Hier wurde es wirklich schwierig.

Ich dachte, die Lösung wäre, einfach die zweite Animation zu überspringen. So tat ich. Was passiert, ist eine flüssige Animation von 1 bis 7 mit 0 Schluckauf. Perfekt! Wenn Sie jedoch wischen oder sogar auf den Bildschirm tippen, befinden Sie sich plötzlich (ohne Animation) bei Element 6! Wenn Sie von 7 auf 1 gewischt haben, befinden Sie sich tatsächlich bei Element 2. Es wird weder setCurrentItem (2) aufgerufen noch der OnPageChangeListener aufgerufen, der angibt, dass Sie zu einem beliebigen Zeitpunkt bei 2 angekommen sind.

Aber du bist eigentlich nicht bei Element 2, was irgendwie gut ist. Sie befinden sich noch bei Element 1, aber die Ansicht für Element 2 wird angezeigt. Wenn Sie dann nach links wischen, gelangen Sie zu Element 1. Auch wenn Sie sich bereits in Element 1 befunden haben.

Animation ist kaputt, aber keine seltsamen Nebenwirkungen

@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
    super.startScroll(startX, startY, dx, dy, duration);
}

Animation funktioniert! Aber alles ist seltsam und beängstigend ...

@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
    if (dx > 480 || dx < -480) {
    } else {
        super.startScroll(startX, startY, dx, dy, duration);
    }
}

Der einzige Unterschied ist, dass wir die zweite Animation (größer als die Breite des 480-Pixel-Bildschirms) ignorieren, wenn sie aufgerufen wird.

Nachdem ich den Android-Quellcode für Scroller gelesen hatte, stellte ich fest, dass startScroll nicht mit dem Scrollen beginnt. Es werden alle zu scrollenden Daten eingerichtet, es wird jedoch nichts initiiert.

Meine Vermutung

Wenn Sie die zirkuläre Aktion ausführen (1 bis 7 oder 7 bis 1), gibt es zwei Aufrufe von startScroll (). Ich denke, dass etwas zwischen den beiden Anrufen ein Problem verursacht.

Der Benutzer scrollt von Element 1 zu Element 7, wodurch ein Sprung von 0 nach 7 verursacht wird. Dies sollte sich nach links bewegen.startScroll () wird aufgerufen und zeigt links eine kurze Animation an.PERSONAL PASSIERT, DASS MICH MÖGLICHERWEISE SCHREIEN LÄSST, DENKE ICHstartScroll () heißt und gibt a anlange Animation zumRecht.Es erfolgt eine lange Animation rechts.

Wenn ich 4 auskommentiere, wird 5 zu "Kurze korrekte Animation links, die Dinge werden verrückt".

Zusammenfassung

Meine Implementierung eines Circular ViewPagers funktioniert, aber die Animation ist fehlerhaft. Beim Versuch, die Animation zu reparieren, wird die Funktionalität des ViewPagers beeinträchtigt. Ich drehe gerade meine Räder und versuche herauszufinden, wie es funktioniert. Hilf mir! :)

Wenn etwas unklar ist, kommentieren Sie bitte unten und ich werde klären. Mir ist klar, dass ich nicht sehr genau wusste, wie die Dinge kaputt sind. Es ist schwer zu beschreiben, da nicht einmal klar ist, was ich auf dem Bildschirm sehe. Wenn meine Erklärung ein Problem ist, an dem ich arbeiten kann, lass es mich wissen!

Prost, Coltin

Code

Dieser Code wurde leicht modifiziert, um die Lesbarkeit zu verbessern, obwohl die Funktionalität mit meiner aktuellen Iteration des Codes identisch ist.

OnPageChangeListener.onPageSelected

@Override
public void onPageSelected(int _position) {
    boolean animate = true;
    if (_position < 1) {
        // Swiping left past the first element, go to element (9 - 2)=7
        setCurrentItem(getAdapter().getCount() - 2, animate);
    } else if (_position >= getAdapter().getCount() - 1) {
        // Swiping right past the last element
        setCurrentItem(1, animate);
    }
}

CircularScroller.startScroll

@Override
public void startScroll(int _startX, int _startY, int _dx, int _dy, int _duration) {
    // 480 is the width of the screen
    if (dx > 480 || dx < -480) {
        // Doing nothing in this block shows the correct animation,
        // but it causes the issues mentioned above

        // Uncomment to do the big scroll!
        // super.startScroll(_startX, _startY, _dx, _dy, _duration);

        // lastDX was to attempt to reset the scroll to be the previous
        // correct scroll distance; it had no effect
        // super.startScroll(_startX, _startY, lastDx, _dy, _duration);
    } else {
        lastDx = _dx;
        super.startScroll(_startX, _startY, _dx, _dy, _duration);
    }
}

CircularViewPageAdapter.CircularViewPageAdapter

private static final int m_Length = 7; // For our example only
private static Context m_Context;
private boolean[] created = null; // Not the best practice..

public CircularViewPageAdapter(Context _context) {
    m_Context = _context;
    created = new boolean[m_Length];
    for (int i = 0; i < m_Length; i++) {
        // So that we do not create things multiple times
        // I thought this was causing my issues, but it was not
        created[i] = false;
    }
}

CircularViewPageAdapter.getCount

@Override
public int getCount() {
    return m_Length + 2;
}

CircularViewPageAdapter.instantiateItem

@Override
public Object instantiateItem(View _collection, int _position) {

    int virtualPosition = getVirtualPosition(_position);
    if (created[virtualPosition - 1]) {
        return null;
    }

    TextView tv = new TextView(m_Context);
    // The first view is element 1 with label 0! :)
    tv.setText("Bonjour, merci! " + (virtualPosition - 1));
    tv.setTextColor(Color.WHITE);
    tv.setTextSize(30);

    ((ViewPager) _collection).addView(tv, 0);

    return tv;
}

CircularViewPageAdapter.destroyItem

@Override
public void destroyItem(ViewGroup container, int position, Object view) {
    ViewPager viewPager = (ViewPager) container;
    // If the virtual distance is distance 2 away, it should be destroyed.
    // If it's not intuitive why this is the case, please comment below
    // and I will clarify
    int virtualDistance = getVirtualDistance(viewPager.getCurrentItem(), getVirtualPosition(position));
    if ((virtualDistance == 2) || ((m_Length - virtualDistance) == 2)) {
        ((ViewPager) container).removeView((View) view);
        created[getVirtualPosition(position) - 1] = false;
    }
}

Antworten auf die Frage(1)

Ihre Antwort auf die Frage