我有一个包括recyclerView
和tabLayout
的界面,当用户切换标签时,recyclerView
会加载新的条目。现在我想添加滑动功能,当用户在recyclerView
上向左或向右滑动时,应用程序可以在标签之间进行切换(并重新加载recyclerView
中的新条目)。我一直很难有效地检测到在recyclerView
上向左或向右滑动手势。我不想使用ViewPager,因为我想保持我的应用程序轻巧快速。此外,我只需要滑动这一功能。以下是我最后使用的方法:
OnSwipeTouchListener onSwipeTouchListener = new OnSwipeTouchListener(getActivity())
{
public void onSwipeRight() {
//update recyclerview with new data
}
public void onSwipeLeft(){
//update recyclerview with new data
}
};
b.rcvItems.setOnTouchListener(onSwipeTouchListener);
b.rcvItems.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0) {
int threshold = 20;
int count = adapter.getItemCount();
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int lastVisible = layoutManager.findLastVisibleItemPosition();
if (lastVisible >= count - threshold) {
//load more items
}
}
}
});
这里是类OnSwipeTouchListener
,其中包含类GestureListener
:
public class OnSwipeTouchListener implements View.OnTouchListener {
private final GestureDetector gestureDetector;
protected OnSwipeTouchListener(Context ctx) {
gestureDetector = new GestureDetector(ctx, new GestureListener());
}
@Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
public void onSwipeRight() {
}
public void onSwipeLeft() {
}
public void onSwipeTop() {
}
public void onSwipeBottom() {
}
private final class GestureListener extends GestureDetector.SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 23;
private static final int SWIPE_VELOCITY_THRESHOLD = 0;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
result = true;
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
}
现在问题是当加载
Fragment
时,首先,滑动功能无法使用。但是在我滚动recyclerView
或者有时在尝试多次滑动后,它开始检测到滑动动作!然后就变得流畅了。我检查发现,在方法onFling()
中的第一个参数MotionEvent e1在我第一次滚动recyclerView
之前或尝试多次滑动后为null。仍然在某些启动中,滑动功能即使在最初也能正常工作!(这很少见,但确实会发生)。这太复杂了,我甚至无法确定正确的行为方式。我该如何解决这个问题?附注:有时应用程序会冻结,然后崩溃。我获取以下崩溃日志:
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionMyViewHolder{779d2db position=27 id=-1, oldPos=-1, pLpos:-1 no parent} androidx.recyclerview.widget.RecyclerView{2415051 VFED..... ........ 0,0-1080,2049 #7f09016d app:id/rcvItems}, adapter:ui.adapter.ItemsAdapter@bee10b6, layout:androidx.recyclerview.widget.LinearLayoutManager@38c1b7, context:ui.MainActivity@577a61c
at androidx.recyclerview.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5972)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6156)
at androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:288)
at androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:345)
at androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:361)
at androidx.recyclerview.widget.GapWorker.prefetch(GapWorker.java:368)
at androidx.recyclerview.widget.GapWorker.run(GapWorker.java:399)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:8167)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)