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:
- void onScroll (AbsListView-Ansicht, int firstVisibleItem, int visibleItemCount, int totalItemCount)
- 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:
quelle
SCROLL_STATE_IDLE
? Wie wenn scrollStateSCROLL_STATE_FLING
oder istSCROLL_STATE_TOUCH_SCROLL
.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. =)
quelle
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 } });
quelle
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; } });
quelle
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; } });
quelle
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 inpreviousDistanceFromFirstCellToTop
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 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; };
quelle
View firstCell = view.getChildAt(0);
Hinzufügen:if(firstCell == null){ return; }
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;
quelle
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) { } }
quelle
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 } });
quelle
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; }
quelle
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
quelle
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:
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:
quelle
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(); } } }
quelle
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);
quelle
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
quelle
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.
quelle
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",""); } });
quelle