每次滑动整个item的RecyclerView(实现viewpager效果),支持水平和垂直滑动
import android.content.Context; import android.support.annotation.Nullable; import android.support.v4.view.VelocityTrackerCompat; import android.support.v7.widget.LinearLayoutManager; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import java.lang.annotation.ElementType; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * Created by lijing on 2017/8/19. */ public class ScrollOneItemRecyclerView extends RecyclerView { private int height, width; private int lastPosition; private int oldScrollState; private VelocityTracker mVelocityTracker; private int downX, downY; private boolean isFirstDown; private boolean canFocus; private boolean canTouchChangePage = true;//是否可以手动换页 public ScrollOneItemRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); this.height = h; this.width = w; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: isFirstDown = true; canFocus = true; downX = (int) ev.getX(); downY = (int) ev.getY(); break; case MotionEvent.ACTION_MOVE: if (isFirstDown) { isFirstDown = false; int x = (int) ev.getX(); int y = (int) ev.getY(); int disX = Math.abs(x - downX); int disY = Math.abs(y - downY); LayoutManager layoutManager = getLayoutManager(); if (layoutManager != null) { final boolean canScrollVertically = layoutManager.canScrollVertically(); if (disX <= 1 && disY <= 1) { canFocus = false; } else if (disX >= disY) { canFocus = !canScrollVertically; } else { canFocus = canScrollVertically; } } } break; } return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent e) { if (!canTouchChangePage) { return false; } else { return super.onInterceptTouchEvent(e); } } @Override public boolean onTouchEvent(MotionEvent e) { if (!canTouchChangePage) return true;//不能手动换页,,就是,recyclerview不能滑动,只能不执行super的onTouchEvent if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } boolean eventAddedToVelocityTracker = false; LayoutManager layoutManager = getLayoutManager(); if (layoutManager == null) return false; final boolean canScrollHorizontally = layoutManager.canScrollHorizontally(); final boolean canScrollVertically = layoutManager.canScrollVertically(); final MotionEvent vtev = MotionEvent.obtain(e); switch (e.getAction()) { case MotionEvent.ACTION_MOVE: return super.onTouchEvent(e) && canFocus; case MotionEvent.ACTION_UP: { mVelocityTracker.addMovement(vtev); eventAddedToVelocityTracker = true; mVelocityTracker.computeCurrentVelocity(1000, 8000); final float xvel = canScrollHorizontally ? -VelocityTrackerCompat.getXVelocity(mVelocityTracker, e.getPointerId(0)) : 0; final float yvel = canScrollVertically ? -VelocityTrackerCompat.getYVelocity(mVelocityTracker, e.getPointerId(0)) : 0; if (((int) xvel == 0) && ((int) yvel == 0)) { if (layoutManager instanceof LinearLayoutManager) { int firstPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); View child = layoutManager.findViewByPosition(firstPosition); int x = (int) e.getX(); int y = (int) e.getY(); int disX = Math.abs(x - downX); int disY = Math.abs(y - downY); if (canScrollHorizontally) { if (disX > 100) { int right = child.getRight(); if (right > width / 2) { fling(-5000, 0); } else { fling(5000, 0); } } } else if (canScrollVertically) { if (disY > 100) { int bottom = child.getBottom(); if (bottom > height / 2) { fling(0, -5000); } else { fling(0, 5000); } } } } } } } if (!eventAddedToVelocityTracker) { mVelocityTracker.addMovement(vtev); } vtev.recycle(); return super.onTouchEvent(e); } /** * @param velocityX * @param velocityY recyclerview向上滑动为正 * @return */ @Override public boolean fling(int velocityX, int velocityY) { LayoutManager layoutManager = getLayoutManager(); if (layoutManager instanceof LinearLayoutManager) { int position = -1; if (layoutManager.canScrollVertically()) { if (velocityY > 0) { position = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); View child = layoutManager.findViewByPosition(position); int top = child.getTop(); int dis = height - (height - top); smoothScrollBy(0, dis, velocityX, Math.max(velocityY, 5000)); } else { position = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); View child = layoutManager.findViewByPosition(position); int bottom = child.getBottom(); int dis = bottom - height; smoothScrollBy(0, dis, velocityX, Math.min(velocityY, -5000)); } } if (layoutManager.canScrollHorizontally()) { if (velocityX > 0) { position = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); View child = layoutManager.findViewByPosition(position); int left = child.getLeft(); int dis = width - (width - left); smoothScrollBy(dis, 0, Math.max(velocityX, 5000), velocityY); } else { position = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); View child = layoutManager.findViewByPosition(position); int right = child.getRight(); int dis = right - width; smoothScrollBy(dis, 0, Math.max(velocityX, -5000), velocityY); } } if (onPagerChangedListener != null) { onPagerChangedListener.onPagerChanged(lastPosition, position); } lastPosition = position; } return true; } public void smoothScrollBy(int dx, int dy, int vx, int vy) { try { Class c = null; try { c = Class.forName("android.support.v7.widget.RecyclerView");//获得Class对象 } catch (ClassNotFoundException e) { e.printStackTrace(); return; } /** * 对应代码 * if (mLayout == null) { * Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " + * "Call setLayoutManager with a non-null argument."); * return; * } */ Field mLayoutField = c.getDeclaredField("mLayout");//根据属性名称,获得类的属性成员Field mLayoutField.setAccessible(true);//设置为可访问状态 LayoutManager mLayout = null; try { mLayout = (LayoutManager) mLayoutField.get(this);//获得该属性对应的对象 if (mLayout == null) { return; } } catch (IllegalAccessException e) { e.printStackTrace(); return; } /** * 对应代码 * if (mLayoutFrozen) { * return; * } */ Field mLayoutFrozen = c.getDeclaredField("mLayoutFrozen"); mLayoutFrozen.setAccessible(true); try { if ((Boolean) mLayoutFrozen.get(this)) { return; } } catch (IllegalAccessException e) { e.printStackTrace(); return; } /** * 对应代码 * if (!mLayout.canScrollHorizontally()) { * dx = 0; * } */ if (!mLayout.canScrollHorizontally()) { dx = 0; } /** * 对应代码 * if (!mLayout.canScrollVertically()) { * dy = 0; * } */ if (!mLayout.canScrollVertically()) { dy = 0; } /** * 对应代码 * if (dx != 0 || dy != 0) { * mViewFlinger.smoothScrollBy(dx, dy); * } * 此处调用mViewFlinger.smoothScrollBy(dx, dy, duration);这是我们的目的。 */ Field mViewFlingerField = c.getDeclaredField("mViewFlinger"); mViewFlingerField.setAccessible(true); try { Class ViewFlingerClass = null; try { //由于内部类是私有的,所以不能直接得到内部类名, //通过mViewFlingerField.getType().getName() //可以得到私有内部类的完整类名 ViewFlingerClass = Class.forName(mViewFlingerField.getType().getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); return; } //根据方法名,获得我们的目标方法对象。第一个参数是方法名,后面的是该方法的入参类型。 // 注意Integer.class与int.class的不同。 Method smoothScrollBy = ViewFlingerClass.getDeclaredMethod("smoothScrollBy", int.class, int.class, int.class, int.class); smoothScrollBy.setAccessible(true);//设置为可操作状态 if (dx != 0 || dy != 0) { Log.d("MySmoothScrollBy", "dx=" + dx + " dy=" + dy); try { //唤醒(调用)方法, // mViewFlingerField.get(this)指明是哪个对象调用smoothScrollBy。 // dx, dy, duration 是smoothScrollBy所需参数 smoothScrollBy.invoke(mViewFlingerField.get(this), dx, dy, vx, vy); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } catch (NoSuchMethodException e) { e.printStackTrace(); return; } } catch (NoSuchFieldException e) { return; } } public void setCanTouchChangePage(boolean canTouchChangePage) { this.canTouchChangePage = canTouchChangePage; } private OnPagerChangedListener onPagerChangedListener; public void setOnPagerChangedListener(OnPagerChangedListener onPagerChangedListener) { this.onPagerChangedListener = onPagerChangedListener; } public interface OnPagerChangedListener { void onPagerChanged(int lastPosition, int position); } }