Erkennen Sie Scroll Up & Scroll Down in ListView


71

Ich habe folgende Anforderung:

  • Zunächst werden Daten für Seite Nr. 2 vom Server abgerufen und die Elemente in einer ListView ausgefüllt.

In Anbetracht der Tatsache, dass sowohl die vorherige als auch die nächste Seite in einem Szenario verfügbar sind, wurde der folgende Code hinzugefügt:

 if(prevPageNo > 0){
    mListViewActual.setOnScrollListener(this);
 }

 if(nextPageNo > 0){
    mListViewActual.setOnScrollListener(this);
 }

Welche Bedingungen sollte ich stellen, um das Scrollen nach oben und nach unten bei den folgenden Methoden zu erkennen:

  1. void onScroll (AbsListView-Ansicht, int firstVisibleItem, int visibleItemCount, int totalItemCount)
  2. void onScrollStateChanged (AbsListView-Ansicht, int scrollState)

Nachdem die Aktion: Bildlauf nach oben und Bildlauf nach unten erkannt wurde, wird dementsprechend ein Dienst mit der vorherigen Seitennummer oder der nächsten Seitennummer aufgerufen, um die Elemente abzurufen, die in der Listenansicht ausgefüllt werden sollen.

Alle Eingaben sind hilfreich.

Die folgenden Links sind durchgegangen, aber es wird nicht die richtige Aktion zum Auf- und Abblättern zurückgegeben:

Link 1 Link 2

Antworten:


94

Versuchen Sie es mit dem setOnScrollListener und implementieren Sie den onScrollStateChanged mit scrollState

setOnScrollListener(new OnScrollListener(){
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
      // TODO Auto-generated method stub
    }
    public void onScrollStateChanged(AbsListView view, int scrollState) {
      // TODO Auto-generated method stub
      final ListView lw = getListView();

       if(scrollState == 0) 
      Log.i("a", "scrolling stopped...");


        if (view.getId() == lw.getId()) {
        final int currentFirstVisibleItem = lw.getFirstVisiblePosition();
         if (currentFirstVisibleItem > mLastFirstVisibleItem) {
            mIsScrollingUp = false;
            Log.i("a", "scrolling down...");
        } else if (currentFirstVisibleItem < mLastFirstVisibleItem) {
            mIsScrollingUp = true;
            Log.i("a", "scrolling up...");
        }

        mLastFirstVisibleItem = currentFirstVisibleItem;
    } 
    }
  });

2
Was ist, wenn Sie die Bildlaufrichtung vor dem scollState bestimmen möchten SCROLL_STATE_IDLE? Wie wenn scrollState SCROLL_STATE_FLINGoder ist SCROLL_STATE_TOUCH_SCROLL.
toobsco42

4
Was für mich funktioniert, ist das Hinzufügen dieses Codes bei OnScroll, nicht bei onScrollStateChanged
Ayman Mahgoub,

wird nicht funktionieren, wenn alle Elemente sichtbar sind, zum Beispiel wenn Sie 2 Elemente haben und wie WhatsApp nach oben scrollen möchten, um mehr zu laden
Leres Aldtai

63

Hier ist eine funktionierende modifizierte Version einiger der oben angegebenen Lösungen.

Fügen Sie eine weitere Klasse ListView hinzu:

package com.example.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AbsListView;

public class ListView extends android.widget.ListView {

    private OnScrollListener onScrollListener;
    private OnDetectScrollListener onDetectScrollListener;

    public ListView(Context context) {
        super(context);
        onCreate(context, null, null);
    }

    public ListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        onCreate(context, attrs, null);
    }

    public ListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        onCreate(context, attrs, defStyle);
    }

    @SuppressWarnings("UnusedParameters")
    private void onCreate(Context context, AttributeSet attrs, Integer defStyle) {
        setListeners();
    }

    private void setListeners() {
        super.setOnScrollListener(new OnScrollListener() {

            private int oldTop;
            private int oldFirstVisibleItem;

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if (onScrollListener != null) {
                    onScrollListener.onScrollStateChanged(view, scrollState);
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (onScrollListener != null) {
                    onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
                }

                if (onDetectScrollListener != null) {
                    onDetectedListScroll(view, firstVisibleItem);
                }
            }

            private void onDetectedListScroll(AbsListView absListView, int firstVisibleItem) {
                View view = absListView.getChildAt(0);
                int top = (view == null) ? 0 : view.getTop();

                if (firstVisibleItem == oldFirstVisibleItem) {
                    if (top > oldTop) {
                        onDetectScrollListener.onUpScrolling();
                    } else if (top < oldTop) {
                        onDetectScrollListener.onDownScrolling();
                    }
                } else {
                    if (firstVisibleItem < oldFirstVisibleItem) {
                        onDetectScrollListener.onUpScrolling();
                    } else {
                        onDetectScrollListener.onDownScrolling();
                    }
                }

                oldTop = top;
                oldFirstVisibleItem = firstVisibleItem;
            }
        });
    }

    @Override
    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.onScrollListener = onScrollListener;
    }

    public void setOnDetectScrollListener(OnDetectScrollListener onDetectScrollListener) {
        this.onDetectScrollListener = onDetectScrollListener;
    }
}

Und eine Schnittstelle:

public interface OnDetectScrollListener {

    void onUpScrolling();

    void onDownScrolling();
}

Und schließlich, wie man verwendet:

com.example.view.ListView listView = (com.example.view.ListView) findViewById(R.id.list);
listView.setOnDetectScrollListener(new OnDetectScrollListener() {
    @Override
    public void onUpScrolling() {
        /* do something */
    }

    @Override
    public void onDownScrolling() {
        /* do something */
    }
});

In Ihrem XML-Layout:

<com.example.view.ListView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

Dies ist mein erstes Thema, beurteilen Sie mich nicht hart. =)


Genau das habe ich gesucht. Klappt wunderbar! +1!
Nari Kim Shin

Das ist sehr genau !! Vielen Dank
Krit

1
Warum nicht den Scroll-Listener anstelle der gesamten Ansicht erweitern? Das Erweitern der Ansicht nur für das Bildlaufereignis ist nicht gerade eine gute Vorgehensweise, insbesondere wenn Sie später einen neuen
Bildlauflistener

46

Dies ist eine einfache Implementierung:

lv.setOnScrollListener(new OnScrollListener() {
        private int mLastFirstVisibleItem;

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {

        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {

            if(mLastFirstVisibleItem<firstVisibleItem)
            {
                Log.i("SCROLLING DOWN","TRUE");
            }
            if(mLastFirstVisibleItem>firstVisibleItem)
            {
                Log.i("SCROLLING UP","TRUE");
            }
            mLastFirstVisibleItem=firstVisibleItem;

        }
    });

Wenn Sie mehr Präzision benötigen, können Sie diese benutzerdefinierte ListView-Klasse verwenden:

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;

/**
 * Created by root on 26/05/15.
 */
public class ScrollInterfacedListView extends ListView {


    private OnScrollListener onScrollListener;
    private OnDetectScrollListener onDetectScrollListener;

    public ScrollInterfacedListView(Context context) {
        super(context);
        onCreate(context, null, null);
    }

    public ScrollInterfacedListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        onCreate(context, attrs, null);
    }

    public ScrollInterfacedListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        onCreate(context, attrs, defStyle);
    }

    @SuppressWarnings("UnusedParameters")
    private void onCreate(Context context, AttributeSet attrs, Integer defStyle) {
        setListeners();
    }

    private void setListeners() {
        super.setOnScrollListener(new OnScrollListener() {

            private int oldTop;
            private int oldFirstVisibleItem;

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if (onScrollListener != null) {
                    onScrollListener.onScrollStateChanged(view, scrollState);
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (onScrollListener != null) {
                    onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
                }

                if (onDetectScrollListener != null) {
                    onDetectedListScroll(view, firstVisibleItem);
                }
            }

            private void onDetectedListScroll(AbsListView absListView, int firstVisibleItem) {
                View view = absListView.getChildAt(0);
                int top = (view == null) ? 0 : view.getTop();

                if (firstVisibleItem == oldFirstVisibleItem) {
                    if (top > oldTop) {
                        onDetectScrollListener.onUpScrolling();
                    } else if (top < oldTop) {
                        onDetectScrollListener.onDownScrolling();
                    }
                } else {
                    if (firstVisibleItem < oldFirstVisibleItem) {
                        onDetectScrollListener.onUpScrolling();
                    } else {
                        onDetectScrollListener.onDownScrolling();
                    }
                }

                oldTop = top;
                oldFirstVisibleItem = firstVisibleItem;
            }
        });
    }

    @Override
    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.onScrollListener = onScrollListener;
    }

    public void setOnDetectScrollListener(OnDetectScrollListener onDetectScrollListener) {
        this.onDetectScrollListener = onDetectScrollListener;
    }


    public interface OnDetectScrollListener {

        void onUpScrolling();

        void onDownScrolling();
    }

}

Ein Beispiel für die Verwendung: (Vergessen Sie nicht, es als XML-Tag in Ihre layout.xml einzufügen.)

scrollInterfacedListView.setOnDetectScrollListener(new ScrollInterfacedListView.OnDetectScrollListener() {
            @Override
            public void onUpScrolling() {
               //Do your thing
            }

            @Override
            public void onDownScrolling() {

             //Do your thing
            }
        });

Grundsätzlich funktioniert es nicht für kleine Schriftrollen. Dies implementiert einen "eins nach dem anderen" Detektor. Es wird nur ausgelöst, wenn Sie "eine ganze Zelle" gescrollt haben.
Fattie

Ich glaube, dass dies perfekt funktioniert (wenn man bedenkt, dass es zellbezogen und nicht pixelweise ist). Ich habe es ausgiebig getestet, verglichen mit der unten stehenden Methode "Vier Tests" (Beispiel Elulicis Antwort). Hoffe es hilft jemandem.
Fattie

1
Tolle und einfache Lösung.
LJ Wilson

Großartig! Funktioniert perfekt!
KinGPinG

Einfachste Lösung, die ich bekommen habe, danke
Chintan Desai

12

Bei allen veröffentlichten Methoden treten Probleme beim Erkennen auf, wenn der Benutzer vom ersten Element nach oben oder vom letzten nach unten scrollt. Hier ist ein weiterer Ansatz zum Erkennen des Bildlaufs nach oben / unten:

        listView.setOnTouchListener(new View.OnTouchListener() {
            float height;
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                float height = event.getY();
                if(action == MotionEvent.ACTION_DOWN){
                    this.height = height;
                }else if(action == MotionEvent.ACTION_UP){
                    if(this.height < height){
                        Log.v(TAG, "Scrolled up");
                    }else if(this.height > height){
                        Log.v(TAG, "Scrolled down");
                    }
                }
                return false;
            }
        });

Verhindert dies, dass das untergeordnete Element von viewView berührt wird, oder klicken Sie auf?
Noor Hossain

Ich will das nur, danke!
Noor Hossain

10
            ListView listView = getListView();
            listView.setOnScrollListener(new OnScrollListener() {

                @Override
                public void onScrollStateChanged(AbsListView view, int scrollState) {

                    view.setOnTouchListener(new OnTouchListener() {
                        private float mInitialX;
                        private float mInitialY;

                        @Override
                        public boolean onTouch(View v, MotionEvent event) {
                            switch (event.getAction()) {
                                case MotionEvent.ACTION_DOWN:
                                    mInitialX = event.getX();
                                    mInitialY = event.getY();
                                    return true;
                                case MotionEvent.ACTION_MOVE:
                                    final float x = event.getX();
                                    final float y = event.getY();
                                    final float yDiff = y - mInitialY;
                                    if (yDiff > 0.0) {
                                        Log.d(tag, "SCROLL DOWN");
                                        scrollDown = true;
                                        break;

                                    } else if (yDiff < 0.0) {
                                        Log.d(tag, "SCROLL up");
                                        scrollDown = true;
                                        break;

                                    }
                                    break;
                            }
                            return false;
                        }
                    });

Dies ist wirklich die beste Lösung dafür, da alle anderen Lösungen vom aktuellen und letzten sichtbaren Element abhängen. Wenn Sie vom Listenelement abhängig sind, sind Sie auch vom Adapter abhängig. Wenn Sie scrollen und der Adapter das nächste Element nicht aufgeblasen hat, wissen Sie nicht, ob der Benutzer nach oben oder unten gescrollt hat.
Koc

3
Dies ist wirklich eine SCHLECHTE Lösung, da Sie den View Touch Listener JEDES Mal auf ScrollStateChanged einstellen, was viel Overhead hat.
Sadegh

8

Meine Lösung funktioniert perfekt und gibt den genauen Wert für jede Bildlaufrichtung an. distanceFromFirstCellToTopenthält den genauen Abstand von der ersten Zelle zum oberen Rand der übergeordneten Ansicht. Ich speichere diesen Wert in previousDistanceFromFirstCellToTopund vergleiche ihn beim Scrollen mit dem neuen Wert. Wenn es niedriger ist, habe ich nach oben gescrollt, sonst habe ich nach unten gescrollt.

private int previousDistanceFromFirstCellToTop;

listview.setOnScrollListener(new OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        View firstCell = listview.getChildAt(0);
        int distanceFromFirstCellToTop = listview.getFirstVisiblePosition() * firstCell.getHeight() - firstCell.getTop();

        if(distanceFromFirstCellToTop < previousDistanceFromFirstCellToTop)
        {
           //Scroll Up
        }
        else if(distanceFromFirstCellToTop  > previousDistanceFromFirstCellToTop)
        {
           //Scroll Down
        }
        previousDistanceFromFirstCellToTop = distanceFromFirstCellToTop;
    }
});

Für Xamarin-Entwickler lautet die Lösung wie folgt:

Hinweis: Vergessen Sie nicht, auf dem UI-Thread auszuführen

listView.Scroll += (o, e) =>
{
    View firstCell = listView.GetChildAt(0);
    int distanceFromFirstCellToTop = listView.FirstVisiblePosition * firstCell.Height - firstCell.Top;

    if (distanceFromFirstCellToTop < previousDistanceFromFirstCellToTop)
    {
        //Scroll Up
    }
    else if (distanceFromFirstCellToTop > previousDistanceFromFirstCellToTop)
    {
        //Scroll Down
    }
    previousDistanceFromFirstCellToTop = distanceFromFirstCellToTop;
};

1
Gute Antwort! Ich musste nur eine Überprüfung hinzufügen, ob die erste Zelle null ist (weil es passieren kann, dass sie noch nicht aufgeblasen ist).
Peshkira

Das ist die beste und einfachste Antwort, die ich zum Erkennen der Bildlaufrichtung gefunden habe! Es ist richtig, auch wenn die Artikelhöhe klein oder groß ist. Es funktioniert perfekt und stabil. VIELEN DANK. Übrigens, nur eine Kleinigkeit , Sie können die Variable previousDistanceFromFirstCellToTop in die innere anonyme OnScrollListener- Klasse einfügen , um sie zu verbessern .
Denken Sie zweimal Code einmal

1
Tolle Lösung! Nur eines fehlt: nach dem View firstCell = view.getChildAt(0); Hinzufügen:if(firstCell == null){ return; }
Mark Kazakov

4

Stellen Sie einfach den Bildlauf-Listener auf Ihre Listenansicht ein.

Wenn Sie eine Kopf- oder Fußzeile haben, sollten Sie auch die sichtbare Anzahl überprüfen. Wenn es zunimmt, bedeutet dies, dass Sie nach unten scrollen. (Umkehren, wenn anstelle der Kopfzeile eine Fußzeile vorhanden ist)

Wenn Ihre Listenansicht keine Kopf- oder Fußzeile enthält, können Sie die Zeilen entfernen, die die Anzahl der sichtbaren Elemente beeinträchtigen.

listView.setOnScrollListener(new AbsListView.OnScrollListener() {
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            if (mLastFirstVisibleItem > firstVisibleItem) {
                Log.e(getClass().toString(), "scrolling up");
            } else if (mLastFirstVisibleItem < firstVisibleItem) {
                Log.e(getClass().toString(), "scrolling down");
            } else if (mLastVisibleItemCount < visibleItemCount) {
                Log.e(getClass().toString(), "scrolling down");
            } else if (mLastVisibleItemCount > visibleItemCount) {
                Log.e(getClass().toString(), "scrolling up");
            }
            mLastFirstVisibleItem = firstVisibleItem;
            mLastVisibleItemCount = visibleItemCount;
        }

        public void onScrollStateChanged(AbsListView listView, int scrollState) {
        }
    });

und haben diese Variablen

int mLastFirstVisibleItem;
int mLastVisibleItemCount;

Dies funktioniert nur, wenn Sie "eine ganze Zelle" verschieben. Es erkennt keine kleinen Bewegungen. Es funktioniert zuverlässig. Beachten Sie, dass es ausgelöst wird, wenn ein Zellenrand den unteren Rand des Bildschirms passiert (oder was auch immer einschließt), nicht den oberen. Alter, ich bin sicher, du hast übrigens auf und ab transponiert!
Fattie

Ich kann keinen Unterschied in der Funktion zwischen dieser Antwort und dem einfacheren Ansatz, z. B. GaiRom oben, feststellen. Ich habe Eckkoffer etc. ausgiebig getestet. Gab es einen Grund für die zusätzlichen Vergleiche, Eluleci?
Fattie

4

Ich habe diese viel einfachere Lösung verwendet:

setOnScrollListener( new OnScrollListener() 
{

    private int mInitialScroll = 0;

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) 
    {
        int scrolledOffset = computeVerticalScrollOffset();

        boolean scrollUp = scrolledOffset > mInitialScroll;
        mInitialScroll = scrolledOffset;
    }


    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {


    }

}

Was ist computeVerticalScrollOffset?
Fattie

2
Eine geschützte Methode in ListView
Vaiden

Vielen Dank für die schnelle Antwort. Ich scheine nicht in der Lage zu sein, es zu benutzen: Ich bekomme nur "Symbol kann nicht gefunden werden ..." Ich habe alle Ansichten ausprobiert. computeVerticalScrollOffset (), myListView.computeVerticalScrollOffset () und rufen Sie es einfach in Ihrem Code auf. Entschuldigung, ich bin neu in Android von iOS (und ich liebe Android!)
Fattie

2
Da es sich um eine geschützte Methode handelt, müssen Sie ListView erweitern.
Vaiden

4

Um auch das Scrollen mit größeren Elementen zu erkennen, bevorzuge ich einen onTouch Listener:

listview.setOnTouchListener(new View.OnTouchListener() {

        int scrollEventListSize = 5; 
        float lastY;
        // Used to correct for occasions when user scrolls down(/up) but the onTouchListener detects it incorrectly. We will store detected up-/down-scrolls with -1/1 in this list and evaluate later which occured more often
        List<Integer> downScrolledEventsHappened;

        @Override
        public boolean onTouch(View v, MotionEvent event) {

            float diff = 0;
            if(event.getAction() == event.ACTION_DOWN){
                lastY = event.getY();
                downScrolledEventsHappened = new LinkedList<Integer>();
            }
            else if(event.getAction() == event.ACTION_MOVE){
                diff = event.getY() - lastY;
                lastY = event.getY();

                if(diff>0)
                    downScrolledEventsHappened.add(1);
                else 
                    downScrolledEventsHappened.add(-1);

               //List needs to be filled with some events, will happen very quickly
                if(downScrolledEventsHappened.size() == scrollEventListSize+1){
                    downScrolledEventsHappened.remove(0);
                    int res=0;
                    for(int i=0; i<downScrolledEventsHappened.size(); i++){
                        res+=downScrolledEventsHappened.get(i);
                    }

                    if (res > 0) 
                        Log.i("INFO", "Scrolled up");
                    else 
                        Log.i("INFO", "Scrolled down");
                }
            }
            return false; // don't interrupt the event-chain
        }
    });

3

Speichern Sie das erste sichtbare Element und überprüfen Sie beim nächsten onScroll, ob das neue erste sichtbare Element kleiner oder größer als das vorherige ist.

Beispiel Pseudocode (nicht getestet):

int lastVisibleItem = 0;
boolean isScrollingDown = false;

void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    if (firstVisibleItem > lastVisibleItem) {
        isScrollingDown = true;
    }
    else {
        isScrollingDown = false;
    }
    lastVisibleItem = firstVisibleItem;
}

Implementierte den obigen Code. onScroll () wird aufgerufen, wenn der Benutzer einen Bildlauf durchführt und das letzte Element der ListView erreicht. onScroll () wird jedoch nicht aufgerufen, wenn der Benutzer zum ersten sichtbaren Element der ScrollView scrollt. Für die erste Seite erstes sichtbares Element: 0. Wie gehe ich mit dem Szenario um? onScrollStateChanged () wird in beiden Fällen aufgerufen.
Chiranjib

Ich habe einen Code, den onScroll jedes Mal aufruft! Sind Sie sicher, dass der Listener die ganze Zeit läuft? Setzen Sie mListViewActual.setOnScrollListener (this) unabhängig von einer Bedingung!
Thiagolr

Ich habe mListViewActual.setOnScrollListener (this) ohne Bedingung hinzugefügt. Trotzdem wird onScroll () nicht aufgerufen, wenn der Benutzer versucht, nach oben zu scrollen, dh über das oberste sichtbare Element hinaus, das in diesem Fall 0 ist. Derzeit befindet sich der Benutzer, wie bereits erwähnt, auf Seite Nr. 2: Nur wenn der Benutzer versucht, einen Bildlauf durchzuführen Nach oben, dh nachdem das erste sichtbare Element & onScroll () aufgerufen wurde, kann ein nächster Serviceabruf an den Server gesendet werden, um die Daten für Seite Nr. 1
abzurufen

1

Aus irgendeinem Grund deckt das Android-Dokument dies nicht ab, und die verwendete Methode ist nicht einmal in den Dokumenten enthalten. Ich habe eine Weile gebraucht, um sie zu finden.

Um festzustellen, ob sich Ihre Schriftrolle oben befindet, würden Sie dies verwenden.

public boolean checkAtTop() 
{
    if(listView.getChildCount() == 0) return true;
    return listView.getChildAt(0).getTop() == 0;
}

Dadurch wird überprüft, ob sich Ihr Scroller oben befindet. Um dies für den unteren Bereich zu tun, müssten Sie die Anzahl der Kinder, die Sie haben, übergeben und mit dieser Anzahl vergleichen. Möglicherweise müssen Sie herausfinden, wie viele gleichzeitig auf dem Bildschirm angezeigt werden, und dies von Ihrer Anzahl der Kinder abziehen. Ich musste das nie tun. Hoffe das hilft


1

Diese Methoden können nicht verwendet werden, um Bildlaufrichtungen direkt zu erkennen. Es gibt viele Möglichkeiten, die Richtung zu bestimmen. Ein einfacher Code (ungetestet) für eine solche Methode wird nachfolgend erläutert:

öffentliche Klasse ScrollTrackingListView erweitert ListView {

    private boolean readyForMeasurement = false;
    private Boolean isScrollable = null;
    private float prevDistanceToEnd = -1.0;
    privater ScrollDirectionListener Listener = null;

    public ScrollTrackingListView (Kontextkontext) {
        super (Kontext);
        drin();
    }}

    public ScrollTrackingListView (Kontextkontext, AttributeSet-Attribute) {
        super (Kontext, attrs);
        drin();
    }}

    public ScrollTrackingListView (Kontextkontext, AttributeSet-Attribute, int defStyle) {
        super (Kontext, attrs, defStyle);
        drin();
    }}

    private void init () {
        ViewTreeObserver Observer = getViewTreeObserver ();
        Observer.addOnGlobalLayoutListener (globalLayoutListener);
        setOnScrollListener (scrollListener);
    }}

    privater ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener
            = neuer ViewTreeObserver.OnGlobalLayoutListener () {

        @Override
        public void onGlobalLayout () {
            readyForMeasurement = true;
            berechneDistanzToEnd ();
        }}

    };

    public void registerScrollDirectionListener (ScrollDirectionListener-Listener) {
        scrollDirectionListener = Listener;
    }}

    public void unregisterScrollDirectionListener () {
        scrollDirectionListener = null;
    }}

    privater OnScrollListener scrollListener
            = neuer OnScrollListener () {

        @Override
        public void onScrollStateChanged (AbsListView absListView, int i) {
            berechneDistanzToEnd ();
        }}

        @Override
        public void onScroll (AbsListView absListView, int i, int i1, int i2) {
            // Nichts tun
        }}

    };

    private void berechneDistanceToEnd () {

        if (readyForMeasurement) {

            // Ich verwende die Höhe des Layouts, die horizontale Bildlaufleiste und
            // Inhalt zusammen mit Offset nach unten scrollen

            // computeVerticalScrollExtent wird verwendet, um die Länge des Daumens in der Spur der Bildlaufleiste zu berechnen.
            // Die Länge des Daumens ist eine Funktion der Ansichtshöhe und der Inhaltslänge.
            int verticalScrollExtent = computeVerticalScrollExtent ();
            int verticalScrollOffset = computeVerticalScrollOffset ();
            int verticalScrollRange = computeVerticalScrollRange ();
            int horizontalScrollBarHeight = getHorizontalScrollbarHeight ();

            / **
             * 1. "R" soll den Bereich der vertikalen Bildlaufleiste darstellen. Dies entspricht der Länge des Inhalts
             * in der Ansicht.
             * 2. "E" soll die Ausdehnung der vertikalen Bildlaufleiste darstellen. Das Ausmaß ist ein konstanter Wert und ist
             * (wahrscheinlich) gleich einem Wert proportional zur Höhe der Ansicht.
             * 3. Der Versatz "o" repräsentiert die aktuelle Position in dem Bereich, der für den Benutzer sichtbar ist. Es kann dauern
             * Werte von "0 bis E".
             * *
             * Jetzt wird das DistanceToEnd mit diesen drei Werten wie folgt berechnet:
             * *
             * DistanceToEnd = (R - o) / E.
             * *
             * DistanceToEnd enthält den Wert in NumberOfScreenToEnd-Einheiten.
             * *
             * /

            float distanceToEnd =
                    )

            if (prevDistanceToEnd == -1) {
                 prevDistanceToEnd = distanceToEnd;
            } else {
                 if (Listener! = null) {
                     if (distanceToEnd> prevDistanceToEnd) {
                        // Benutzer scrollt nach oben
                         listener.onScrollingUp ();
                     } else {
                        // Benutzer scrollt nach oben
                         listener.onScrollingDown ();
                    }}
                 }}
                 prevDistanceToEnd = distanceToEnd;
            }}

            if (isScrollable == null) {
                // Überprüfen Sie, ob die Ansichtshöhe kleiner als ein Bildschirm ist (dh es ist kein Bildlauf aktiviert).
                if ((horizontalScrollBarHeight + vertikaleScrollExtent)> = vertikaleScrollRange) {
                    isScrollable = Boolean.FALSE;
                } else {
                    isScrollable = Boolean.TRUE;
                }}
            }}

        }}

    }}

    öffentliche Schnittstelle ScrollDirectionListener {

        public void onScrollingUp ();

        public void onScrollingDown ();

    }}

}}

Die Idee ist, den distanceToEnd zu berechnen. Wenn distanceToEnd zunimmt, scrollt der Benutzer nach oben und wenn es abnimmt, scrollt der Benutzer nach unten. Dadurch erhalten Sie auch den genauen Abstand zum Ende der Liste.

Wenn Sie nur versuchen zu wissen, ob der Benutzer nach oben oder unten scrollt , können Sie das onInterceptTouchEvent überschreiben , um die Bildlaufrichtung wie folgt zu erkennen:

    @Override
    public boolean onInterceptTouchEvent (MotionEvent-Ereignis) {
        switch (event.getAction ()) {
            case MotionEvent.ACTION_DOWN:
                mInitialX = event.getX ();
                mInitialY = event.getY ();
                return true;
            case MotionEvent.ACTION_MOVE:
                final float x = event.getX ();
                final float y = event.getY ();
                final float yDiff = y - mInitialY; // yDiff kleiner als 0.0 bedeutet einen Bildlauf nach unten, während yDiff größer als 0.0 einen Bildlauf nach oben bedeutet. Wenn ich versuche, die Symbole kleiner oder größer als hinzuzufügen, wird sie in der Vorschau nicht angezeigt.
                if (yDiff kleiner als 0.0) listener.onScrollingDown ();
                sonst wenn (yDiff größer als 0.0) listener.onScrollingUp ();
                Unterbrechung;
        }}
        return super.onInterceptTouchEvent (Ereignis);
    }}


1

Trick zum Erkennen von Bildlauf nach oben oder unten in der Listenansicht. Rufen Sie diese Funktion einfach in der onScroll-Funktion in OnScrollListener von ListView auf.

private int oldFirstVisibleItem = -1;
    private protected int oldTop = -1;
    // you can change this value (pixel)
    private static final int MAX_SCROLL_DIFF = 5;

    private void calculateListScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (firstVisibleItem == oldFirstVisibleItem) {
            int top = view.getChildAt(0).getTop();
            // range between new top and old top must greater than MAX_SCROLL_DIFF
            if (top > oldTop && Math.abs(top - oldTop) > MAX_SCROLL_DIFF) {
                // scroll up
            } else if (top < oldTop && Math.abs(top - oldTop) > MAX_SCROLL_DIFF) {
                // scroll down
            }
            oldTop = top;
        } else {
            View child = view.getChildAt(0);
            if (child != null) {
                oldFirstVisibleItem = firstVisibleItem;
                oldTop = child.getTop();
            }
        }
    }

1

Einfache Methode zum Erkennen von Bildlauf nach oben / unten in der Android-Listenansicht

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount){
  if(prevVisibleItem != firstVisibleItem){
    if(prevVisibleItem < firstVisibleItem)
      //ScrollDown
    else
      //ScrollUp

  prevVisibleItem = firstVisibleItem;
}

nicht vergessen

yourListView.setOnScrollListener(yourScrollListener);

0

Folgendes würde ich zuerst versuchen:

1) Erstellen Sie eine Schnittstelle (nennen wir sie OnScrollTopOrBottomListener) mit folgenden Methoden:

void onScrollTop ();

void onScrollBottom ();

2) Fügen Sie im Adapter Ihrer Liste eine Mitgliedsinstanz hinzu, die als von Ihnen erstellte Schnittstelle eingegeben wurde, und geben Sie einen Setter und einen Getter an.

3) Überprüfen Sie in der getView () -Implementierung Ihres Adapters, ob der Positionsparameter entweder 0 oder getCount () - 1 ist. Überprüfen Sie auch, ob Ihre OnScrollTopOrBottomListener-Instanz nicht null ist.

4) Wenn die Position 0 ist, rufen Sie onScrollTopOrBottomListener.onScrollTop () auf. Wenn position getCount () - 1 ist, rufen Sie onScrollTopOrBottomListener.onScrollBottom () auf.

5) Rufen Sie in Ihrer OnScrollTopOrBottomListener-Implementierung die entsprechenden Methoden auf, um die gewünschten Daten abzurufen.

Hoffe das hilft irgendwie.

-Brandon


0

Ich habe Probleme mit einem Beispiel festgestellt, bei dem die Zellengröße von ListView großartig ist. So habe ich eine Lösung für mein Problem gefunden, die die geringste Bewegung Ihres Fingers erkennt. Ich habe auf das Minimum vereinfacht und ist wie folgt:

private int oldScrolly;


@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {

}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int    visibleItemCount, int totalItemCount) {

            View view = absListView.getChildAt(0);
            int scrolly = (view == null) ? 0 : -view.getTop() + absListView.getFirstVisiblePosition() * view.getHeight();
            int margin = 10;

            Log.e(TAG, "Scroll y: " + scrolly + " - Item: " + firstVisibleItem);


            if (scrolly > oldScrolly + margin) {
                Log.d(TAG, "SCROLL_UP");
                oldScrolly = scrolly;
            } else if (scrolly < oldScrolly - margin) {
                Log.d(TAG, "SCROLL_DOWN");
                oldScrolly = scrolly;
            }
        }
    });

PD: Ich benutze den MARGIN, um die Schriftrolle erst zu erkennen, wenn Sie diesen Rand erreicht haben. Dies vermeidet Probleme beim Ein- oder Ausblenden von Ansichten und vermeidet das Blinken.


0

Einfache Möglichkeit, mehr Elemente beim Scrollen nach oben / unten in Android GridView zu laden

    grid.setOnScrollListener(new AbsListView.OnScrollListener() {
                private int mLastFirstVisibleItem;
                @Override
                public void onScrollStateChanged(AbsListView view, int scrollState) {
                    // TODO Auto-generated method stub
                    Log.d("state",String.valueOf(scrollState));


                    if(scrollState == 0)
                        Log.i("a", "scrolling stopped...");


                    if (view.getId() == grid.getId()) {

                        final int currentFirstVisibleItem = grid.getLastVisiblePosition();
                        mLastFirstVisibleItem = grid.getFirstVisiblePosition();

                        if (currentFirstVisibleItem > mLastFirstVisibleItem) {
                            mIsScrollingUp = false;
                            if(!next.contains("null")){

                           //Call api to get products from server

                             }


                            Log.i("a", "scrolling down...");
                        } else if (currentFirstVisibleItem < mLastFirstVisibleItem) {
                            mIsScrollingUp = true;
                            Log.i("a", "scrolling up...");
                        }

                        mLastFirstVisibleItem = currentFirstVisibleItem;
                    }

                }
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                Log.d("on scroll","");
            }
        });
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.