Overview
RecycleView implements infinite repetition of specific data, in my opinion, there are only two ways.
1. Modify the adpter multiplexing mechanism to reuse data infinitely
2. Return the data length in adpter and return the maximum value of Integer
Since the first type can achieve infinite repetition of data, the data bits still have no change, so when it automatically jumps to the end, it cannot be carouseled to the next bit, so here I use the second way to achieve automatic carousel
Briefly describe the multiplexing mechanism of modifying adpter
Let's take LinearLayoutManager as an example. We just need to re-play LinearLayoutManager to do some tricks and feet when drawing.
package ; import ; import ; import ; import ; import ; import ; import ; import ; import ; /** * @author Version: 1.0 * Created date: 2020/4/14 14 * describe: */ public class ScrollSpeedLinearLayoutManger extends LinearLayoutManager { public ScrollSpeedLinearLayoutManger(Context context) { super(context); } public ScrollSpeedLinearLayoutManger(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } public ScrollSpeedLinearLayoutManger(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public generateDefaultLayoutParams() { return new (.WRAP_CONTENT,.WRAP_CONTENT); } // 1 When the RecyclerView is initialized, it will be called twice.// 2 When calling(), it will be called.// 3 When calling setAdapter to replace Adapter, it will be called.// 4 It will also be called when the RecyclerView executes an animation. @Override public void onLayoutChildren( recycler, state) { ("TAG","onLayoutChildren "); if (getItemCount() == 0){ detachAndScrapAttachedViews(recycler); return; } //() supports animation if (getItemCount() == 0 && ()){ return; } //Remove all the views in the current Recycler and put them in the scrap cache, and then reuse the views in the cache first. detachAndScrapAttachedViews(recycler); int actualHeight = 0; for (int i = 0 ;i < getItemCount() ; i++){ View scrap = (i); addView(scrap); measureChildWithMargins(scrap,0,0); int width = getDecoratedMeasuredWidth(scrap); int height = getDecoratedMeasuredHeight(scrap); layoutDecorated(scrap,0,actualHeight,width,actualHeight+height); actualHeight+=height; //If you go beyond the interface, you won't draw it, and you won't add it. if (actualHeight > getHeight()){ break; } } } @Override public boolean canScrollVertically() { return true; } @Override public int scrollVerticallyBy(int dy, recycler, state) { ("feifeifei","getChildCount() " + getChildCount() + " ().size() " + ().size()); //When the interface scrolls down, dy is positive, dy is negative when scrolling upward, dy is negative when scrolling upward //filling fill(dy,recycler,state); //scroll offsetChildrenVertical(dy*-1); //Recycling has left the interface recycleOut(dy,recycler,state); return dy; } private void fill(int dy, recycler, state){ //Scroll down if (dy > 0){ //Fill in the bottom first View lastView = getChildAt(getChildCount() -1); int lastPos = getPosition(lastView); if (() - dy < getHeight()){ View scrap; if (lastPos == getItemCount() -1){ scrap = (0); }else { scrap = (lastPos+1); } addView(scrap); measureChildWithMargins(scrap,0,0); int width = getDecoratedMeasuredWidth(scrap); int height = getDecoratedMeasuredHeight(scrap); layoutDecorated(scrap,0,(),width,()+height); } }else { //Scroll up //The top fill now View firstView = getChildAt(0); int layoutPostion = getPosition(firstView); if (() >= 0 ){ View scrap ; if (layoutPostion == 0){ scrap = (getItemCount()-1); }else { scrap = (layoutPostion -1); } addView(scrap,0); measureChildWithMargins(scrap,0,0); int width = getDecoratedMeasuredWidth(scrap); int height = getDecoratedMeasuredHeight(scrap); layoutDecorated(scrap,0,() - height,width,()); } } } private void recycleOut(int dy, recycler, state){ for (int i = 0 ; i <getChildCount() ;i++){ View view = getChildAt(i); if (dy >0){ if (()-dy <0){ ("feifeifei","recycleOut " + i); removeAndRecycleView(view,recycler); } }else { if (()-dy > getHeight()){ ("feifeifei","recycleOut " + i); removeAndRecycleView(view,recycler); } } } } @Override public void smoothScrollToPosition(RecyclerView recyclerView, state, int position) { smoothScroller = new CenterSmoothScroller(()); (position); startSmoothScroll(smoothScroller); } private class CenterSmoothScroller extends LinearSmoothScroller { public CenterSmoothScroller(Context context) { super(context); } protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { return 0.2f; } } }
This is probably the grid that is written in this way, you need to rewrite it yourself because there will be differences in calculations. Here I will briefly explain it.
Main topic
Implementation of Adapter Adapter
There is no difference in writing. The only getItemCount and onBindViewHolder need to be processed as follows
public class AdAuditorAdapter extends <> { private Context mContext; private List<String> mData; public AdAuditorAdapter(Context mContext, List<String> mData) { = mContext; = mData; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { MyViewHolder holder = new MyViewHolder((mContext).inflate(.item_adauditor, viewGroup, false)); return holder; } @Override public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, @SuppressLint("RecyclerView") int i) { ("HHHHHHHHH", "onBindViewHolder: -->"+i ); //Fetch the remaining, otherwise the index will be crossed. myViewHolder.tv_1.setText((i%())); (new () { @Override public void onClick(View v) { (v, i%(), 3); } }); } @Override public int getItemCount() { //Return the maximum adpter value return Integer.MAX_VALUE; } public void update(List<String> list) { = list; notifyDataSetChanged(); } class MyViewHolder extends { TextView tv_1; public MyViewHolder(@NonNull View itemView) { super(itemView); tv_1 = (.tv_1); //ID } } public MyClickListener getListener() { return listener; } public void setMyClickListener(MyClickListener listener) { = listener; } MyClickListener listener; public interface MyClickListener { void onClick(View view, int position, int type); } public List<String> getData() { return mData; } }
Implementation of activity
1 Basic implementation
1.1 Add fake data to write a click event
1.2 Use handler to delay sending a message (position); move to the specified location
1.3 Click to stop moving
2 Effect optimization
2.1 Add uniform damping effect
2.2 Implementing infinite carousel to consider the case that the value exceeds the Integer maximum value
2.3 When clicking on the recycleview when it is being rotated, the carousel will stop, and clicking again will execute the click event (optimized to click stop and execute the click event)
The damping effect is to reduce the sliding rate
We do
package ; import ; import ; import ; import ; import ; import ; import ; import ; import ; /** * @author Version: 1.0 * Created date: 2020/4/14 14 * describe: */ public class ScrollSpeedGridLayoutManager1 extends GridLayoutManager { public ScrollSpeedGridLayoutManager1(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } public ScrollSpeedGridLayoutManager1(Context context, int spanCount) { super(context, spanCount); } public ScrollSpeedGridLayoutManager1(Context context, int spanCount, int orientation, boolean reverseLayout) { super(context, spanCount, orientation, reverseLayout); } @Override public void smoothScrollToPosition(RecyclerView recyclerView, state, int position) { smoothScroller = new CenterSmoothScroller(()); (position); startSmoothScroll(smoothScroller); } private class CenterSmoothScroller extends LinearSmoothScroller { public CenterSmoothScroller(Context context) { super(context); } protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { return 10f;//Sliding rate problem } } }
Activity all codes
package ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; /** * @author Version: 1.0 * Created date: 2020/4/14 14 * describe: */ public class RecycleViewActivity extends AppCompatActivity { static RecyclerView rv_1; private static int HANDLER_MSG = 0x0011; private static int HANDLER_LONG_MSG = 0x0021; static int position = 0; static int addNum = 3; @SuppressLint("HandlerLeak") private static Handler handler = new Handler() { @Override public void handleMessage(@NonNull Message msg) { if ( == HANDLER_MSG) { // The 9 grid effect is the same rate if (addNum==3){ position = position + addNum; addNum = 6; }else { position = position + addNum; addNum = 3; } ("TAG", "handleMessage: -->" + position); smoothMoveToPosition(rv_1, position >= 0 ? position : 0); if (position==Integer.MAX_VALUE/2){ //Click or reset adapter by more than 2% of Integer.MAX_VALUE LongAutoMove(); }else { AutoMove(); } }else if (==HANDLER_LONG_MSG){ position = 0; addNum = 3; ("TAG", "handleMessage: -->" + position); smoothMoveToPosition(rv_1, 0); AutoMove(); } } }; private static AdAuditorAdapter adAuditorAdapter; static List<String> strings; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { (savedInstanceState); setContentView(.activity_recycle); rv_1 = findViewById(.rv_1); strings = new ArrayList<>(); for (int i = 0; i < 50; i++) { (i + ""); } adAuditorAdapter = new AdAuditorAdapter(this, strings); (new () { @Override public void onClick(View view, int position, int type) { (, ().get(position), Toast.LENGTH_SHORT).show(); StopMove(); } }); GridLayoutManager layoutManager = new ScrollSpeedGridLayoutManager1(this,3,, false); rv_1.setLayoutManager(layoutManager); rv_1.setAdapter(adAuditorAdapter); rv_1.addOnScrollListener(new () { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { (recyclerView, newState); // if (mShouldScroll && RecyclerView.SCROLL_STATE_IDLE == newState) { // mShouldScroll = false; // smoothMoveToPosition(recyclerView, mToPosition); // } ("TAG", "onScrollStateChanged11111111: -->" + newState); if (newState == 1) { // holder = (()); (new () { @Override public void onClick(View v) { (, ().get(position)+"........", Toast.LENGTH_SHORT).show(); } }); StopMove(); LongAutoMove(); } } // @Override // public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { // (recyclerView, dx, dy); // ("TAG", "onScrolled: dx=" +dx +" dy="+dy ); // } }); rv_1.setOnTouchListener(new () { @Override public boolean onTouch(View v, MotionEvent event) { if (()==MotionEvent.ACTION_DOWN){ // Monitor the click position and find the view to realize the click event View childView = rv_1.findChildViewUnder((), ()); ("GGGGGGGGGGGGGGGGG", "onTouch: -->"+rv_1.getChildLayoutPosition(childView)); ().onClick(v, rv_1.getChildLayoutPosition(childView),1); } return false; } }); AutoMove(); } private static void AutoMove() { (HANDLER_MSG); (HANDLER_MSG, 2000); } private static void LongAutoMove() { if ((HANDLER_MSG)) { (HANDLER_LONG_MSG); } (HANDLER_LONG_MSG, 5000); } public static void StopMove() { if ((HANDLER_MSG)) { (HANDLER_MSG); } } //Is the target item after the last visible item private static boolean mShouldScroll; //Record the target item position private static int mToPosition; /** * Slide to the specified position */ private static void smoothMoveToPosition(RecyclerView mRecyclerView, final int position) { if (position==0){ (adAuditorAdapter); } (position); mToPosition = position; mShouldScroll = true; } @Override protected void onDestroy() { (); if (handler!=null){ (null); handler= null; } if (adAuditorAdapter!=null) { adAuditorAdapter= null; } } }
Basic implementation of automatic carousel effect
The demo here only writes about the approximate effect and there are many things that need to be optimized before it can be used in the project.
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.