利用RecyclerView实现无限循环滚动
一、先上效果图
滚动
二、GitHub地址
GitHub地址 https://github.com/MNXP/AutomaticRolling
三、思路
RecycleView实现,内部实现Runnable滚动
四、实现
1)内部实现Runnable
static class AutoPollTask implements Runnable {
private final WeakReference mReference;
/**
* 使用弱引用持有外部类引用,防止内存泄漏
*/
private AutoPollTask(AutoPollRecyclerView reference) {
this.mReference = new WeakReference<>(reference);
}
@Override
public void run() {
AutoPollRecyclerView recyclerView = mReference.get();
if (recyclerView != null && recyclerView.running) {
recyclerView.scrollBy(2, 2);//每次滚动距离
/**
* 判断是否为无限循环
*/
if (recyclerView.canRun){
/**
* 判断是否触底
*/
if (isSlideToBottom(recyclerView)) {
/**跳至顶部*/
recyclerView.smoothScrollToPosition(0);
}
}
recyclerView.postDelayed(recyclerView.autoPollTask,TIME_AUTO_POLL);
}
}
}
/**判断Recycler是否滑动至最底部 是返回true 不是返回false*/
public static boolean isSlideToBottom(RecyclerView recyclerView) {
if (recyclerView == null) return false;
if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset()
>= recyclerView.computeVerticalScrollRange())
return true;
return false;
}
2)开启滚动
//开启
public void start() {
if (running){
return;
}
canRun = true;
running = true;
postDelayed(autoPollTask,TIME_AUTO_POLL);
}
public void setCanRun(boolean canRun){
this.canRun = canRun;
}
3)设置最大高度(没用到可以去掉)
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(widthSpec, heightSpec);
int heightMode = MeasureSpec.getMode(heightSpec);
int heightSize = MeasureSpec.getSize(heightSpec);
if (heightMode == MeasureSpec.EXACTLY) {
heightSize = heightSize <= mMaxHeight ? heightSize
: (int) mMaxHeight;
}
if (heightMode == MeasureSpec.UNSPECIFIED) {
heightSize = heightSize <= mMaxHeight ? heightSize
: (int) mMaxHeight;
}
if (heightMode == MeasureSpec.AT_MOST) {
heightSize = heightSize <= mMaxHeight ? heightSize
: (int) mMaxHeight;
}
int maxHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize,
heightMode);
super.onMeasure(widthSpec, maxHeightMeasureSpec);
}
4)自身Adapter设置
@Override
public int getItemCount() {
if (mData!=null){
if (mData.size()<=3)
return mData.size();
else
return mData.size()*20;//return Integer.MAX_VALUE;
}else {
return 0;
}
}
5)引用
autoPollRecyclerView = (AutoPollRecyclerView) itemView.findViewById(R.id.main_recycler);
autoPollRecyclerView.start();
autoPollRecyclerView.setNestedScrollingEnabled(false);
autoPollRecyclerView.setLayoutManager(new LinearLayoutManager(context,LinearLayoutManager.VERTICAL, false));
((SimpleItemAnimator) autoPollRecyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
/**
* 我的是超过3项开始滚动
*/
if (item.list.size() > 0) {
if (item.list.size() <= 3) {
viewHolder.autoPollRecyclerView.setCanRun(false);
} else {
viewHolder.autoPollRecyclerView.setCanRun(true);
}
}
6)自动滚动RecycleView完整代码
public class AutoPollRecyclerView extends RecyclerView {
private static final long TIME_AUTO_POLL = 30;
private AutoPollTask autoPollTask;
private boolean running; //是否正在自动轮询
private boolean canRun;//是否可以自动轮询,可在不需要的是否置false
private int mMaxHeight;//最大高度
public AutoPollRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
autoPollTask = new AutoPollTask(this);
mMaxHeight = dip2px(context,100);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return false;
}
static class AutoPollTask implements Runnable {
private final WeakReference mReference;
/**
* 使用弱引用持有外部类引用,防止内存泄漏
*/
private AutoPollTask(AutoPollRecyclerView reference) {
this.mReference = new WeakReference<>(reference);
}
@Override
public void run() {
AutoPollRecyclerView recyclerView = mReference.get();
if (recyclerView != null && recyclerView.running) {
recyclerView.scrollBy(2, 2);//每次滚动距离
/**
* 判断是否为无限循环
*/
if (recyclerView.canRun){
/**
* 判断是否触底
*/
if (isSlideToBottom(recyclerView)) {
/**跳至顶部*/
recyclerView.smoothScrollToPosition(0);
}
}
recyclerView.postDelayed(recyclerView.autoPollTask,TIME_AUTO_POLL);
}
}
}
/**判断Recycler是否滑动至最底部 是返回true 不是返回false*/
public static boolean isSlideToBottom(RecyclerView recyclerView) {
if (recyclerView == null) return false;
if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset()
>= recyclerView.computeVerticalScrollRange())
return true;
return false;
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(widthSpec, heightSpec);
int heightMode = MeasureSpec.getMode(heightSpec);
int heightSize = MeasureSpec.getSize(heightSpec);
if (heightMode == MeasureSpec.EXACTLY) {
heightSize = heightSize <= mMaxHeight ? heightSize
: (int) mMaxHeight;
}
if (heightMode == MeasureSpec.UNSPECIFIED) {
heightSize = heightSize <= mMaxHeight ? heightSize
: (int) mMaxHeight;
}
if (heightMode == MeasureSpec.AT_MOST) {
heightSize = heightSize <= mMaxHeight ? heightSize
: (int) mMaxHeight;
}
int maxHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize,
heightMode);
super.onMeasure(widthSpec, maxHeightMeasureSpec);
}
//开启
public void start() {
if (running){
return;
}
canRun = true;
running = true;
postDelayed(autoPollTask,TIME_AUTO_POLL);
}
public void setCanRun(boolean canRun){
this.canRun = canRun;
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
7)小小的建议
RecycleView实现,首页列表,加载图片有卡顿
卡顿优化可以使用vLayout(阿里开源库)处理挺好的,它只要是用于处理列表不同布局
vLayout地址 (https://github.com/alibaba/vlayout)
如有意见和建议,及时沟通。