可以无限滚动,支持自动滚动,设置滚动一屏幕时间的LayoutManger
package com.trs.v7.home.toutiao_v2.provider.layout_manager;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.PagerSnapHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.trs.news.R;
public class LooperLayoutManager extends RecyclerView.LayoutManager {
private static final String TAG = "LooperLayoutManager";
private boolean looperEnable = true;
private RecyclerView recyclerView;
private int pixNumberPer10ms = 3;
private boolean autoScroll = true;
private PagerSnapHelper snapHelper;
public LooperLayoutManager(RecyclerView recyclerView) {
this(recyclerView, true, true, 8000);
}
public LooperLayoutManager(RecyclerView recyclerView, boolean looperEnable, boolean autoScroll, int scrollOneScreenUseTimeInMilliSeconds) {
this.looperEnable = looperEnable;
this.autoScroll = true;
this.recyclerView = recyclerView;
clearLooperInfo(recyclerView);
LooperInfo looperInfo=new LooperInfo();
looperInfo.onScrollListener=onScrollListener;
recyclerView.addOnScrollListener(onScrollListener);
looperInfo.onAttachStateChangeListener=attachStateChangeListener;
this.recyclerView.addOnAttachStateChangeListener(attachStateChangeListener);
int widthPixels = recyclerView.getResources().getDisplayMetrics().widthPixels;
pixNumberPer10ms = (int) (widthPixels * 1.0f / scrollOneScreenUseTimeInMilliSeconds * 10);
pixNumberPer10ms = Math.max(1, pixNumberPer10ms);
if (!autoScroll) {
recyclerView.setOnFlingListener(null);
snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
looperInfo.pagerSnapHelper=snapHelper;
}
looperInfo.runnable=cycleRollRunnable;
bindLooperInfo(recyclerView,looperInfo);
}
private void clearLooperInfo(RecyclerView recyclerView) {
Object tag = recyclerView.getTag(R.id.looper_info);
if(tag instanceof LooperInfo){
LooperInfo looperInfo= (LooperInfo) tag;
recyclerView.removeOnScrollListener(looperInfo.onScrollListener);
recyclerView.removeOnAttachStateChangeListener(looperInfo.onAttachStateChangeListener);
if(looperInfo.pagerSnapHelper!=null) {
looperInfo.pagerSnapHelper.attachToRecyclerView(null);
}
recyclerView.removeCallbacks(looperInfo.runnable);
recyclerView.setTag(R.id.looper_info,null);
}
}
private void bindLooperInfo(RecyclerView recyclerView,LooperInfo looperInfo){
recyclerView.setTag(R.id.looper_info,looperInfo);
}
private static class LooperInfo{
PagerSnapHelper pagerSnapHelper;
RecyclerView.OnScrollListener onScrollListener;
View.OnAttachStateChangeListener onAttachStateChangeListener;
Runnable runnable;
}
private View.OnAttachStateChangeListener attachStateChangeListener = new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
recyclerView.removeCallbacks(cycleRollRunnable);
recyclerView.setTag(R.id.tv_title,cycleRollRunnable);
recyclerView.postDelayed(cycleRollRunnable, 1000);
}
@Override
public void onViewDetachedFromWindow(View v) {
recyclerView.removeCallbacks(cycleRollRunnable);
}
};
@Override
public boolean isAutoMeasureEnabled() {
return true;
}
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
public boolean canScrollHorizontally() {
return true;
}
@Override
public boolean canScrollVertically() {
return false;
}
Runnable cycleRollRunnable = new Runnable() {
@Override
public void run() {
if (autoScroll) {
recyclerView.scrollBy(pixNumberPer10ms, 0);
Object tag = recyclerView.getTag(R.id.tv_title);
if(tag==this) {
recyclerView.postDelayed(this, 10);
}
}
}
};
RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
private boolean dragging;
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
recyclerView.removeCallbacks(cycleRollRunnable);
dragging = true;
} else if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (dragging) {
dragging = false;
recyclerView.removeCallbacks(cycleRollRunnable);
recyclerView.setTag(R.id.tv_title,cycleRollRunnable);
recyclerView.postDelayed(cycleRollRunnable, 1000);
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
};
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getItemCount() <= 0) {
return;
}
if (state.isPreLayout()) {
return;
}
detachAndScrapAttachedViews(recycler);
int autualWidth = 0;
for (int i = 0; i < getItemCount(); i++) {
View itemView = recycler.getViewForPosition(i);
addView(itemView);
measureChildWithMargins(itemView, 0, 0);
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) itemView.getLayoutParams();
int width = getDecoratedMeasuredWidth(itemView) ;
int height = getDecoratedMeasuredHeight(itemView);
int left=autualWidth;
int right=autualWidth+width+lp.rightMargin+lp.leftMargin;
int top=0;
int bottom=height+lp.topMargin+lp.bottomMargin;
layoutDecoratedWithMargins(itemView, left, top, right, bottom);
autualWidth = right;
}
}
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
int travl = fill(dx, recycler, state);
if (travl == 0) {
return 0;
}
offsetChildrenHorizontal(travl * -1);
recyclerHideView(dx, recycler, state);
return travl;
}
private int fill(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
if (dx > 0) {
View lastView = getChildAt(getChildCount() - 1);
if (lastView == null) {
return 0;
}
int lastPos = getPosition(lastView);
if (lastView.getRight() < getWidth()) {
View scrap = null;
if (lastPos == getItemCount() - 1) {
if (looperEnable) {
scrap = recycler.getViewForPosition(0);
} else {
dx = 0;
}
} else {
scrap = recycler.getViewForPosition(lastPos + 1);
}
if (scrap == null) {
return dx;
}
addView(scrap);
measureChildWithMargins(scrap, 0, 0);
RecyclerView.LayoutParams addViewLp = (RecyclerView.LayoutParams) scrap.getLayoutParams();
RecyclerView.LayoutParams lastViewLp = (RecyclerView.LayoutParams) lastView.getLayoutParams();
int width = getDecoratedMeasuredWidth(scrap);
int height = getDecoratedMeasuredHeight(scrap);
int lastViewDecoratedRight = getRightDecorationWidth(lastView);
int left=lastView.getRight()+lastViewDecoratedRight+lastViewLp.rightMargin;
int right=left+width+addViewLp.rightMargin+addViewLp.leftMargin;
int top=0;
int bottom=height+addViewLp.bottomMargin+addViewLp.topMargin;
layoutDecoratedWithMargins(scrap,left,top,right,bottom);
return dx;
}
} else {
View firstView = getChildAt(0);
if (firstView == null) {
return 0;
}
int firstPos = getPosition(firstView);
if (firstView.getLeft() >= 0) {
View scrap = null;
if (firstPos == 0) {
if (looperEnable) {
scrap = recycler.getViewForPosition(getItemCount() - 1);
} else {
dx = 0;
}
} else {
scrap = recycler.getViewForPosition(firstPos - 1);
}
if (scrap == null) {
return 0;
}
addView(scrap, 0);
measureChildWithMargins(scrap, 0, 0);
RecyclerView.LayoutParams addViewLp = (RecyclerView.LayoutParams) scrap.getLayoutParams();
RecyclerView.LayoutParams firstViewLp = (RecyclerView.LayoutParams) firstView.getLayoutParams();
int width = getDecoratedMeasuredWidth(scrap);
int height = getDecoratedMeasuredHeight(scrap);
int decoratedLeft = getLeftDecorationWidth(firstView);
int left=firstView.getLeft()-decoratedLeft-firstViewLp.leftMargin-addViewLp.rightMargin-addViewLp.leftMargin-width;
int right=firstView.getLeft()-decoratedLeft-firstViewLp.leftMargin;
int top=0;
int bottom=height+addViewLp.bottomMargin+addViewLp.topMargin;
layoutDecoratedWithMargins(scrap,left,top,right,bottom);
}
}
return dx;
}
private void recyclerHideView(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
if (view == null) {
continue;
}
if (dx > 0) {
if (view.getRight() < 0) {
removeAndRecycleView(view, recycler);
}
} else {
if (view.getLeft() > getWidth()) {
removeAndRecycleView(view, recycler);
}
}
}
}
}