Introduction: The company’s products need to add the function of suspended advertising bar, the requirement is to be able to rotate, and click the corresponding float bar will jump to the corresponding interface, in the realization of this function encountered some pits, fortunately, finally climbed out of these pits. The main content of this article is to introduce the implementation of the function and the experience of climbing the pit.

Results show

Before the article begins, take a look at the final result, which is shown below

Demand analysis

We already know the product requirements, the following have to do is to analyze how the requirements should be implemented in the first place we want to realize the function is to make the banner circularly, look at the final rendering can be found that the rolling direction is the scroll from down to up, we see the banner of figure is rolling around, rolling around if it is right, This can be done through ViewPager. But how does this scroll up and down work? First of all, the idea is to use the ViewFlipper system control, but this control can only meet the function of the loop scrolling, we also have a requirement is to click on different float bars to jump to different content! The ViewFlipper can’t do that. Both to cycle rolling and each float has the corresponding click event, naturally thought of RecyclerView, RecyclerView is used to realize these needs.

Function implementation

RecyclerView use believe everyone will, but there is a problem here is how to make RecyclerView cycle rolling? Then subdivide the problem, first is how to make RecyclerView itself to scroll, and then how to realize the content cycle inside.

Let’s move! RecyclerView

How do YOU make RecyclerView scroll by itself? By checking the official Api, we found that there is such a method in RecyclerView LayoutManager

The explanation for this method is

Use the provided SmoothScroller to begin smooth scrolling.

Well, now we know the function of this method is to make RecyclerView smooth rolling, since it is to make RecyclerView smooth rolling, then we must tell startSmoothScroll method, how to roll, such as, rolling direction, distance, speed and so on. SmoothScroller is an abstract class that can be used to roll a SmoothScroller. SmoothScroller is an abstract class that can be used to roll a SmoothScroller LinearSmoothScroller is a LinearSmoothScroller that is instantiated directly in the LinearSmoothScroller class. The specific code is as follows

 mSmoothScroller = new LinearSmoothScroller(this) {
            @Override
            protected int getVerticalSnapPreference(a) {
                return LinearSmoothScroller.SNAP_TO_START;
            }

            @Override
            protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
                return 3f/ (displayMetrics.density); }};Copy the code

You can see that two methods are overridden here. GetVerticalSnapPreference rules of the method is to make alignment is RecyclerView inside of the item at the top or bottom and RecyclerView alignment, there are three kinds of alignment, the following is the official document for details of these three alignment

Consider the calculateSpeedPerPixel method, which is used to calculate the speed of scrolling and returns the number of milliseconds it takes to scroll a pixel. Density this is the pixel density of 1dp, which is how many pixels 1dp equals.

Note: SmoothScroller is to scroll the target item into RecyclerView, that is, make the target item visible in RecyclerView.

Now that the scrolling rules are set, the next thing to do is to make the RecyclerView item scroll and recycle it.

Realize RecyclerView cyclic rolling

Before implementing the loop scroll, take a look at the code to implement the scroll, as follows

 private void startAuto(a) {

        if(mAutoTask ! =null && !mAutoTask.isDisposed()) {
            mAutoTask.dispose();
        }
        mAutoTask = Observable.interval(1.2, TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Long>() {

            @Override
            public void accept(Long aLong) {
                mSmoothScroller.setTargetPosition(aLong.intValue());
                RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager();
                if(layoutManager! =null) layoutManager.startSmoothScroll(mSmoothScroller); }}); }Copy the code

As you can see from this code, a circular incrementing timer is implemented using the interval method in RxJava, with an interval of 2s. mSmoothScroller.setTargetPosition(aLong.intValue()); This code sets which item appears in RecyclerView. layoutManager.startSmoothScroll(mSmoothScroller); This code actually calls the start method of the LinearSmoothScroller class. This code implements the function of rolling the set target item smoothly to RecyclerView every two seconds.

Now that I’ve started scrolling, how do I repeat the target item? This is as simple as setting itemCount to infinity, as shown below

@Override
    public int getItemCount(a) {
        return Integer.MAX_VALUE;
    }

@Override
    public void onBindViewHolder(@NonNull final AdViewHolder holder,  int position) {

        if(mDynamicAdsDetails.size() ! =0) {
            String media1 = mDynamicAdsDetails.get(position % mDynamicAdsDetails.size());
            Picasso.get()
                    .load(media1)
                    .error(R.mipmap.ic_launcher)
                    .placeholder(R.mipmap.ic_launcher)
                    .into( holder.ivFlipperItem);

        }
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Control the click frequency
                if ((System.currentTimeMillis() - between) / 1000 < 1) {
                    return;
                }
                between = System.currentTimeMillis();
                Toast.makeText(mContext,"Click on the number"+holder.getAdapterPosition() % mDynamicAdsDetails.size()+"个",Toast.LENGTH_SHORT).show(); }}); }Copy the code

Get (position % mdynamicadsdetails.size ()) mdynamicadsdetails.get (position % mdynamicadsdetails.size ()))

This will allow for cyclic scrolling.

Began to climb the pit

Image confusion problem

This seemed to work fine, but as the project ran, it turned out that instead of showing images in a loop, one image would occasionally appear multiple times before the next. Analysis of the reason, think is RecyclerView reuse problem, the result of asynchronous picture request has not returned back, reuse the last control, so there is a picture display for many times. The solution is to set the ImageView Tag as follows

 if(mDynamicAdsDetails.size() ! =0) {
            String media1 = mDynamicAdsDetails.get(position % mDynamicAdsDetails.size());
            holder.ivFlipperItem.setTag(media1);

            Picasso.get()
                    .load(media1)
                    .error(R.mipmap.ic_launcher)
                    .placeholder(R.mipmap.ic_launcher)
                    .into(new com.squareup.picasso.Target() {
                        @Override
                        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                            if(mDynamicAdsDetails.get(holder.getAdapterPosition() % mDynamicAdsDetails.size()).equals(holder.ivFlipperItem.getTag())) { holder.ivFlipperItem.setScaleType(ImageView.ScaleType.FIT_XY); holder.ivFlipperItem.setImageBitmap(bitmap); }}@Override
                        public void onBitmapFailed(Exception e, Drawable errorDrawable) {}@Override
                        public void onPrepareLoad(Drawable placeHolderDrawable) {}}); }Copy the code

Scroll problem

First look at the problems of sliding RecyclerView, as shown in the figure

It can be found that although you can slide RecyclerView, after sliding, item will go back and continue to scroll at its previous position. There are two ways to solve this problem

  1. Remember the unknown of the item that you manually swipe to, and then inintervalMethod sets the slide position to the target position.
  2. Disable the sliding of RecyclerView.

Since there is no sliding function in the requirement, method 2 is adopted here to prohibit the sliding of RecyclerView. The detailed code is as follows

public class AutoScrollRecyclerView extends RecyclerView {
    private int mState;
    private OnScrollListener mScrollListener;

    public AutoScrollRecyclerView(Context context) {
        this(context,null);
    }

    public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

        @Override
    public boolean onTouchEvent(MotionEvent e) {
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_UP:
                return true;
            case MotionEvent.ACTION_MOVE:
                return false;
            case MotionEvent.ACTION_POINTER_UP:
                return false;
        }
        return true; }}Copy the code

This overrides the RecyclerVieiew onTouchEvent method, which returns false when sliding and does not consume the sliding action.

However, there is a new problem after doing this, that is, when the image is scrolling, we click on the image, the image will pause, the solution used here is to listen to the RecyclerView scrolling state, only when the RecyclerView sliding stopped, do not intercept events, otherwise intercept events. The specific code is as follows

public class AutoScrollRecyclerView extends RecyclerView {
    private int mState;
    private OnScrollListener mScrollListener;

    public AutoScrollRecyclerView(Context context) {
        this(context,null);
    }

    public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mScrollListener = new OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState); mState = newState; }};// Add a slider listener of RecyclerView
        addOnScrollListener(mScrollListener);
    }
    // Determine whether to intercept the event
    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        returnmState ! =0;
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_UP:
                return mState == 0;
            case MotionEvent.ACTION_MOVE:
                return false;
            case MotionEvent.ACTION_POINTER_UP:
                return false;
        }
        return true; }}Copy the code

Well, that solves the problem of sliding RecyclerView.

Customize the AD style

The style of the advertisement can be defined by itself. Not only the picture, but also the text and text can be mixed, etc. All you need to do is modify the layout file. Here, a picture is directly placed in the layout for convenience.

conclusion

The realization of the function is very simple, but if the method of RecyclerView sliding is not familiar with, it is still a little difficult to achieve, there is when we write code not only to achieve the function, but also pay attention to some details, if the details are not good, it is very affect the user experience. Some details of the problem is a test of skills, of course, skills to improve the help is also very great.

Finally, of course, to release the source code, click here to get the source code

Please indicate the source for reprinting: www.wizardev.cn

Scan the code to pay attention to the public number, reply “get information” have surprise