it-swarm.com.de

Erkennen Bildlauf nach oben und Bildlauf nach unten in ListView

Ich habe folgende Anforderungen:

  • Zuerst werden die Daten für Seite 2 vom Server abgerufen und die Elemente in einer ListView aufgefü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 muss ich erfüllen, um einen Bildlauf nach oben und 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)

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

Beliebige Eingaben werden hilfreich sein.

Über die folgenden Links gegangen, aber es wird nicht die richtige Aktion zum Scrollen nach oben/unten zurückgegeben:

Link 1Link 2

68
chiranjib

verwenden Sie den 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;
    } 
    }
  });
90
Sunil Kumar

Hier ist eine funktionierende modifizierte Version von einigen 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 zum Schluss, wie man es benutzt:

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, verurteile mich nicht hart. =)

63
maXp

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 Genauigkeit benötigen, können Sie die folgende 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 Anwendungsbeispiel: (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
            }
        });
44
Gal Rom

Wenn alle Methoden gepostet sind, gibt es Probleme zu erkennen, wann der Benutzer vom ersten Element nach oben oder vom letzten nach unten scrollt. Hier ist ein weiterer Ansatz zum Erkennen von Bildlauf 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;
            }
        });
10
Javier Carmona
            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;
                        }
                    });
10
user1467024

Meine Lösung funktioniert perfekt und gibt den genauen Wert für jede Bildlaufrichtung an. distanceFromFirstCellToTop enthält den genauen Abstand von der ersten Zelle zum oberen Rand der übergeordneten Ansicht. Ich speichere diesen Wert in previousDistanceFromFirstCellToTop und 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 zu laufen

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;
};
8
da Rocha Pires

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

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) {


    }

}
4
Vaiden

Setzen Sie einfach den Scroll-Listener auf Ihre Listenansicht.

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. (Kehren Sie es um, wenn anstelle der Kopfzeile eine Fußzeile vorhanden ist.)

Wenn Sie keine Kopf- oder Fußzeile in Ihrer Listenansicht haben, können Sie die Zeilen entfernen, die die Anzahl der sichtbaren Elemente überprüfen.

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;
3
eluleci

Speichern Sie das firstVisibleItem und überprüfen Sie beim nächsten onScroll, ob das neue firstVisibleItem 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;
}
3
thiagolr

Aus irgendeinem Grund deckt das Android doc dies nicht ab, und die verwendete Methode ist nicht einmal in den Dokumenten ... es hat eine Weile gedauert, bis ich es gefunden habe.

Um festzustellen, ob sich Ihre Schriftrolle oben befindet, verwenden Sie diese Option.

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. Nun, um es für den Boden zu tun, müssten Sie es die Anzahl der Kinder, die Sie haben, übergeben und gegen diese Anzahl überprüfen. Möglicherweise müssen Sie herausfinden, wie viele gleichzeitig auf dem Bildschirm angezeigt werden, und dies von der Anzahl Ihrer Kinder abziehen. Ich musste das nie tun. Hoffe das hilft

1
Shaun

Einfache Möglichkeit zum Erkennen von Bildlauf nach oben/unten auf 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);
1
Rick Royd Aban

Trick um zu erkennen, scrollen Sie in der Listenansicht nach oben oder unten. Rufen Sie diese Funktion einfach in der OnScroll-Funktion im 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
thanhlcm

Ich habe Probleme bei der Verwendung eines Beispiels festgestellt, bei dem die Zellengröße von ListView großartig ist. Ich habe also eine Lösung für mein Problem gefunden, die die geringste Bewegung Ihres Fingers erkennt. Ich habe auf das Minimum vereinfacht und lautet 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 RAND, um die Schriftrolle erst zu erkennen, wenn Sie diesen Rand erreichen. Dies vermeidet Probleme beim Ein- oder Ausblenden von Ansichten und vermeidet deren Blinken.

0

Folgendes würde ich zuerst versuchen:

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

void onScrollTop ();

void onScrollBottom ();

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

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

4) Wenn die Position 0 ist, rufen Sie onScrollTopOrBottomListener.onScrollTop () auf. Wenn die 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
Brandon