Ik moet het begin/einde en de richting van scrollen detecteren in een recyclerview. De scroll-listener heeft twee methoden: onScrolled()
en onScrollStateChanged()
. De eerste methode wordt aangeroepen nadat het scrollen is gestart (het heet inderdaad onScrolled() en niet onScrolling()). De tweede methode geeft informatie over de staat, maar ik heb geen richtingsinformatie. Hoe kan ik mijn doel bereiken?
Antwoord 1, autoriteit 100%
stap 1 U kunt een klasse maken die RecyclerView.OnScrollListener uitbreidt en deze methoden overschrijven
public class CustomScrollListener extends RecyclerView.OnScrollListener {
public CustomScrollListener() {
}
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
switch (newState) {
case RecyclerView.SCROLL_STATE_IDLE:
System.out.println("The RecyclerView is not scrolling");
break;
case RecyclerView.SCROLL_STATE_DRAGGING:
System.out.println("Scrolling now");
break;
case RecyclerView.SCROLL_STATE_SETTLING:
System.out.println("Scroll Settling");
break;
}
}
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dx > 0) {
System.out.println("Scrolled Right");
} else if (dx < 0) {
System.out.println("Scrolled Left");
} else {
System.out.println("No Horizontal Scrolled");
}
if (dy > 0) {
System.out.println("Scrolled Downwards");
} else if (dy < 0) {
System.out.println("Scrolled Upwards");
} else {
System.out.println("No Vertical Scrolled");
}
}
}
stap 2- Aangezien setOnScrollListener verouderd is, is het beter om addOnScrollListener te gebruiken
mRecyclerView.addOnScrollListener(new CustomScrollListener());
Antwoord 2, autoriteit 40%
Zie de documentatie voor onScrollStateChanged(int state)
.
De drie mogelijke waarden zijn:
SCROLL_STATE_IDLE
: er wordt niet gescrolld.SCROLL_STATE_DRAGGING
: de gebruiker sleept zijn vinger over het scherm (of het wordt programmatisch gedaan.SCROLL_STATE_SETTLING
: gebruiker heeft zijn vinger opgetild en de animatie wordt nu langzamer.
Dus als je wilt detecteren wanneer het scrollen begint en eindigt, dan kun je zoiets als dit maken:
public void onScrollStateChanged(int state) {
boolean hasStarted = state == SCROLL_STATE_DRAGGING;
boolean hasEnded = state == SCROLL_STATE_IDLE;
}
Antwoord 3, autoriteit 5%
Gebruik deze code om herhaalde oproepen te vermijden
gebruik -1 voor het detecteren van top
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (!recyclerView.canScrollVertically(1) && newState==RecyclerView.SCROLL_STATE_IDLE) {
Log.d("-----","end");
}
}
});
Antwoord 4, autoriteit 3%
De eenvoudigste manier om dit te doen, is door uw layoutManager tevoorschijn te halen. Bijvoorbeeld
private RecyclerView.OnScrollListener mListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
GridLayoutManager layoutManager=GridLayoutManager.class.cast(recyclerView.getLayoutManager());
int visibleItemCount = layoutManager.getChildCount();
int totalItemCount = layoutManager.getItemCount();
int pastVisibleItems = layoutManager.findFirstCompletelyVisibleItemPosition();
if(pastVisibleItems+visibleItemCount >= totalItemCount){
// End of the list is here.
Log.i(TAG, "End of list");
}
}
}
Hopelijk helpt het!
Antwoord 5, autoriteit 2%
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (!recyclerView.canScrollVertically(1) && newState == RecyclerView.SCROLL_STATE_IDLE) {
//reached end
}
if (!recyclerView.canScrollVertically(-1) && newState == RecyclerView.SCROLL_STATE_IDLE) {
//reached top
}
if(newState == RecyclerView.SCROLL_STATE_DRAGGING){
//scrolling
}
}
Antwoord 6
Ik denk dat de andere antwoorden je pijnpunt niet raken.
Over de vraag
Zoals je zei, zal RecycleView de onScrollStateChanged() aanroepen voor de onScrolled() methode. De methode onScrollStateChanged() kan u echter alleen de drie statussen van RecycleView vertellen:
- SCROLL_STATE_IDLE
- SCROLL_STATE_DRAGGING
- SCROLL_STATE_SETTLING
Dat betekent, neem aan dat de RecycleView nu bovenaan staat, als de gebruiker omhoog scrolt, kan deze alleen de onScrollStateChanged()
-methode activeren, maar niet de onScrolled()
-methode .
En als de gebruiker naar beneden scrolt, kan het eerst de onScrollStateChanged()
-methode activeren en vervolgens de onScrolled()
-methode.
Dan komt het probleem, SCROLL_STATE_DRAGGING
kan je alleen vertellen dat de gebruiker de weergave sleept, niet de richting van zijn slepen.
Je moet combineren met de dy
from onScrolled()
methode om de sleeprichting te detecteren, maar onScrolled()
wordt niet getriggerd met onScrollStateChanged()
.
Mijn Oplossing:
Neem de scrollstatus op wanneer onScrollStateChanged()
werd geactiveerd, stel vervolgens een tijd uit, bijvoorbeeld 10 ms, controleer of er een beweging op de Y-as is en maak een conclusie over de sleeprichting.
Kotlin-code:
class DraggingDirectionScrollListener(private val view: View)
: RecyclerView.OnScrollListener() {
private val DIRECTION_NONE = -1
private val DIRECTION_UP = 0
private val DIRECTION_DOWN = 1
var scrollDirection = DIRECTION_NONE
var listStatus = RecyclerView.SCROLL_STATE_IDLE
var totalDy = 0
override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
listStatus = newState
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
scrollDirection = DIRECTION_NONE
}
if (isOnTop() && newState == RecyclerView.SCROLL_STATE_DRAGGING) {
view.postDelayed({
if (getDragDirection() == DIRECTION_DOWN){
// Drag down from top
}else if (getDragDirection() == DIRECTION_UP) {
// Drag Up from top
}
}, 10)
}
}
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
this.totalDy += dy
scrollDirection = when {
dy > 0 -> DIRECTION_UP
dy < 0 -> DIRECTION_DOWN
else -> DIRECTION_NONE
}
}
/**
* is on the top of the list
*/
private fun isOnTop():Boolean{
return totalDy == 0
}
/**
* detect dragging direction
*/
private fun getDragDirection():Int {
if (listStatus != RecyclerView.SCROLL_STATE_DRAGGING) {
return DIRECTION_NONE
}
return when (scrollDirection) {
DIRECTION_NONE -> if (totalDy == 0){
DIRECTION_DOWN // drag down from top
}else{
DIRECTION_UP // drag up from bottom
}
DIRECTION_UP -> DIRECTION_UP
DIRECTION_DOWN -> DIRECTION_DOWN
else -> DIRECTION_NONE
}
}
}
Antwoord 7
U kunt RecyclerView.getScrollState()
gebruiken voor het detecteren van RecyclerView.SCROLL_STATE_IDLE
of een andere staat.
Mijn zaak:
if (recyclerView?.scrollState != RecyclerView.SCROLL_STATE_IDLE) {
return
}
Antwoord 8
hier is een complete oplossing om een actie uit te voeren nadat het scrollen is gestopt (voor RecyclerView)
die mijn Exception OutOfBounds met betrekking tot het scrollen van recyclerView heeft gecorrigeerd
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
//Your action here
}
});