RecycleView横向自动滚动(ViewPager效果)

场景

项目中要求横向滚动,可自动滚动,可左右滑动。
横向自动滚动.gif

代码

  • AutoPollRecyclerView.java

import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.LinearInterpolator;import java.lang.ref.WeakReference;public class AutoPollRecyclerView extends RecyclerView {private static final long TIME_AUTO_POLL = 2000;AutoPollTask autoPollTask;private boolean running; //标示是否正在自动轮询private boolean canRun;//标示是否可以自动轮询,可在不需要的是否置falsepublic AutoPollRecyclerView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);autoPollTask = new AutoPollTask(this);}static class AutoPollTask implements Runnable {private final WeakReference mReference;//使用弱引用持有外部类引用->防止内存泄漏public AutoPollTask(AutoPollRecyclerView reference) {this.mReference = new WeakReference(reference);}@Overridepublic void run() {AutoPollRecyclerView recyclerView = mReference.get();if (recyclerView != null && recyclerView.running && recyclerView.canRun) {recyclerView.smoothScrollBy(550, 0, new LinearInterpolator());recyclerView.postDelayed(recyclerView.autoPollTask, recyclerView.TIME_AUTO_POLL);}}}//开启:如果正在运行,先停止->再开启public void start() {if (running)stop();canRun = true;running = true;postDelayed(autoPollTask, TIME_AUTO_POLL);}public void stop() {running = false;removeCallbacks(autoPollTask);}@Overridepublic boolean onTouchEvent(MotionEvent e) {switch (e.getAction()) {case MotionEvent.ACTION_DOWN:if (running)stop();break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_OUTSIDE:if (canRun)start();break;}return super.onTouchEvent(e);}
}

调用
mRecycleview.start()


> viewpager效果

GallerySnapHelper.java


import android.graphics.PointF;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SnapHelper;
import android.util.DisplayMetrics;
import android.view.View;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;public class GallerySnapHelper extends SnapHelper {private static final float INVALID_DISTANCE = 1f;private static final float MILLISECONDS_PER_INCH = 40f;private OrientationHelper mHorizontalHelper;private RecyclerView mRecyclerView;@Overridepublic void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException {mRecyclerView = recyclerView;super.attachToRecyclerView(recyclerView);}@Overridepublic int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {int[] out = new int[2];if (layoutManager.canScrollHorizontally()) {out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager));} else {out[0] = 0;}return out;}private int distanceToStart(View targetView, OrientationHelper helper) {return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();}@Nullableprotected LinearSmoothScroller createSnapScroller(final RecyclerView.LayoutManager layoutManager) {if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) {return null;}return new LinearSmoothScroller(mRecyclerView.getContext()) {@Overrideprotected void onTargetFound(View targetView, RecyclerView.State state, Action action) {int[] snapDistances = calculateDistanceToFinalSnap(mRecyclerView.getLayoutManager(), targetView);final int dx = snapDistances[0];final int dy = snapDistances[1];final int time = calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy)));if (time > 0) {action.update(dx, dy, time, mDecelerateInterpolator);}}@Overrideprotected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;}};}@Overridepublic int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) {return RecyclerView.NO_POSITION;}final int itemCount = layoutManager.getItemCount();if (itemCount == 0) {return RecyclerView.NO_POSITION;}final View currentView = findSnapView(layoutManager);if (currentView == null) {return RecyclerView.NO_POSITION;}final int currentPosition = layoutManager.getPosition(currentView);if (currentPosition == RecyclerView.NO_POSITION) {return RecyclerView.NO_POSITION;}RecyclerView.SmoothScroller.ScrollVectorProvider vectorProvider =(RecyclerView.SmoothScroller.ScrollVectorProvider) layoutManager;// deltaJumps sign comes from the velocity which may not match the order of children in// the LayoutManager. To overcome this, we ask for a vector from the LayoutManager to// get the direction.PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1);if (vectorForEnd == null) {// cannot get a vector for the given position.return RecyclerView.NO_POSITION;}//在松手之后,列表最多只能滚多一屏的item数int deltaThreshold = layoutManager.getWidth() / getHorizontalHelper(layoutManager).getDecoratedMeasurement(currentView);int hDeltaJump;if (layoutManager.canScrollHorizontally()) {hDeltaJump = estimateNextPositionDiffForFling(layoutManager,getHorizontalHelper(layoutManager), velocityX, 0);if (hDeltaJump > deltaThreshold) {hDeltaJump = deltaThreshold;}if (hDeltaJump < -deltaThreshold) {hDeltaJump = -deltaThreshold;}if (vectorForEnd.x < 0) {hDeltaJump = -hDeltaJump;}} else {hDeltaJump = 0;}if (hDeltaJump == 0) {return RecyclerView.NO_POSITION;}int targetPos = currentPosition + hDeltaJump;if (targetPos < 0) {targetPos = 0;}if (targetPos >= itemCount) {targetPos = itemCount - 1;}return targetPos;}@Overridepublic View findSnapView(RecyclerView.LayoutManager layoutManager) {return findStartView(layoutManager, getHorizontalHelper(layoutManager));}private View findStartView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) {if (layoutManager instanceof LinearLayoutManager) {int firstChildPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();if (firstChildPosition == RecyclerView.NO_POSITION) {return null;}if (((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition() == layoutManager.getItemCount() - 1) {return null;}View firstChildView = layoutManager.findViewByPosition(firstChildPosition);if (helper.getDecoratedEnd(firstChildView) >= helper.getDecoratedMeasurement(firstChildView) / 2 && helper.getDecoratedEnd(firstChildView) > 0) {return firstChildView;} else {return layoutManager.findViewByPosition(firstChildPosition + 1);}} else {return null;}}private int estimateNextPositionDiffForFling(RecyclerView.LayoutManager layoutManager,OrientationHelper helper, int velocityX, int velocityY) {int[] distances = calculateScrollDistance(velocityX, velocityY);float distancePerChild = computeDistancePerChild(layoutManager, helper);if (distancePerChild <= 0) {return 0;}int distance = distances[0];if (distance > 0) {return (int) Math.floor(distance / distancePerChild);} else {return (int) Math.ceil(distance / distancePerChild);}}private float computeDistancePerChild(RecyclerView.LayoutManager layoutManager,OrientationHelper helper) {View minPosView = null;View maxPosView = null;int minPos = Integer.MAX_VALUE;int maxPos = Integer.MIN_VALUE;int childCount = layoutManager.getChildCount();if (childCount == 0) {return INVALID_DISTANCE;}for (int i = 0; i < childCount; i++) {View child = layoutManager.getChildAt(i);final int pos = layoutManager.getPosition(child);if (pos == RecyclerView.NO_POSITION) {continue;}if (pos < minPos) {minPos = pos;minPosView = child;}if (pos > maxPos) {maxPos = pos;maxPosView = child;}}if (minPosView == null || maxPosView == null) {return INVALID_DISTANCE;}int start = Math.min(helper.getDecoratedStart(minPosView),helper.getDecoratedStart(maxPosView));int end = Math.max(helper.getDecoratedEnd(minPosView),helper.getDecoratedEnd(maxPosView));int distance = end - start;if (distance == 0) {return INVALID_DISTANCE;}return 1f * distance / ((maxPos - minPos) + 1);}private OrientationHelper getHorizontalHelper(RecyclerView.LayoutManager layoutManager) {if (mHorizontalHelper == null) {mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);}return mHorizontalHelper;}}

调用

                            mGallerySnapHelper.attachToRecyclerView(mRecycleView)

总结

  • 自动滚动主要是:开一个定时任务Runnable,recyclerView.smoothScrollBy(550, 0, new LinearInterpolator());
  • 类似viewpager效果 主要是:SnapHelper

参考链接:

  • 一行代码让RecyclerView变身ViewPager
  • Android RecyclerView打造自动循环效果
  • RecyclerView实现Item居中效果(仿猫眼美团电影选择效果)

image

  • 使用RecyclerView实现多行水平分页的GridView效果和ViewPager效果


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部