The usual Android wheel map (common name: Banner) are realized by ViewPager, but I encountered some small problems in the actual project, so I decided to find another way to use RecyclerView this more elegant and powerful control to realize the function of RecyclerView, and review the relevant knowledge of RecyclerView.

implementation

In general, there are only two important parts of a rotation diagram: a picture stream that can slide left and right indefinitely, and a marker for the position of the picture, which may be simpler, even the indicator is omitted. The main difficulty is still in the former, because a rotation map to play the picture is generally ten pieces, do not do any processing directly into RecyclerView inside, not only a little slide on the left and can not start to slide first, So we need to set the total number of Adapter to a large number (can be integer. MAX_VALUE), and then change the current location of RecyclerView to a middle number after setting the image data (in order to ensure that the first image is played, it must be a multiple of the total number of images, Such as 10000*size), so when item is recycled and reused, we only need to take the remainder of the current position and the number of pictures to get the real picture position. Sounds a bit complicated, so let’s go straight to the code:

private class RecyclerAdapter extends RecyclerView.Adapter {
        List<String> urlList;

        public void setData(List<String> urlList) {
            this.urlList = urlList;
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return new RecyclerView.ViewHolder(new ImageView(getContext())) { };
        }

        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            if (urlList == null || urlList.isEmpty())
                return;
            String url = urlList.get(position % bannerSize);
            Glide.with(getContext()).load(url).into((ImageView) holder.itemView);
        }
        @Override
        public int getItemCount() {// Do not slide if there is only one imagereturnbannerSize < 2 ? 1 : Integer.MAX_VALUE; }}Copy the code

For automatic slide images, use Handler to delay sending messages continuously:

private Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == WHAT_AUTO_PLAY) {
                    mRecyclerView.smoothScrollToPosition(++currentIndex);
                 refreshIndicator();
                    mHandler.sendEmptyMessageDelayed(WHAT_AUTO_PLAY, autoPlayDuration);

            }
            return false; }});Copy the code

RecyclerView is used to solve the RecyclerView, so the symbol point is also used to solve it:

  private class IndicatorAdapter extends RecyclerView.Adapter {

        int currentPosition = 0;

        public void setPosition(int currentPosition) {
            this.currentPosition = currentPosition;
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return new RecyclerView.ViewHolder(new ImageView(getContext())) {
            };
        }

        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            ImageView bannerPoint = (ImageView) holder.itemView;
            bannerPoint.setImageDrawable(currentPosition == position ? mSelectedDrawable : mUnselectedDrawable);

        }

        @Override
        public int getItemCount() {
            returnbannerSize; }}Copy the code

The Adapter is as simple as setting an identifier for the current location and notifyDataSetChanged() when the image changes. How good the last leaves to monitor RecyclerView location changed (not as direct as the Viewpager addOnPageChangeListener method), can’t direct analysis RecyclerView. OnScrollListener of the callback methods:

 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {@override public void onScrolled(RecyclerView RecyclerView, int dx, int dy)if (bannerSize < 2) return;
                int firstReal = mLinearLayoutManager.findFirstVisibleItemPosition();
                View viewFirst = mLinearLayoutManager.findViewByPosition(firstReal);
                float width = getWidth();
                if(width ! = 0 && viewFirst ! = null) {float right = viewFirst.getRight();
                    float ratio = right / width;
                    if(thewire > 0.8) {if (currentIndex != firstReal) {
                            currentIndex = firstReal;
                            refreshIndicator();
                        }
                    } else if(thewire < 0.2) {if(currentIndex ! = firstReal + 1) { currentIndex = firstReal + 1; refreshIndicator(); } } } } @Override public void onScrollStateChanged(RecyclerView recyclerView, Int newState because) {/ / continuous sliding may not callback int first. = mLinearLayoutManager findFirstVisibleItemPosition (); int last = mLinearLayoutManager.findLastVisibleItemPosition();if(currentIndex ! = first && first == last) { currentIndex = first; refreshIndicator(); }}});Copy the code

Look at the results

Add some custom View properties, callback methods, interface Settings, and then you’re done. Let’s look at the effect:

gif.gif

Well, it looks good, but why is it weird? Alas, how can this image slide so fast and still stop in the middle, this is not the ‘standard’ rotation image we want. To solve this problem, use another RecyclerView feature: SnapHelper. SnapHelper is designed to support the alignment of RecyclerView by calculating the alignment of the specified TargetView in RecyclerView or any pixel in the container. Customizing a SnapHelper is tricky, but Android already has two built-in implementations: LinearSnapHelper and PagerSnapHelper. PagerSnapHelper is the tool we need to change RecyclerView like Viewpager. new PagerSnapHelper().attachToRecyclerView(mRecyclerView);

gif.gif

It looks much smoother now: you can only slide one image at a time and stop it in the right place. So a basic version of the wheel cast chart is made. Because nature is a RecyclerView, we can RecyclerView. Itemanimator, to make more animation effects (this I’m not too will now (T_T)). Finally, we have github address, which contains more complete code and encapsulates many custom attributes. Welcome star!

PS: Advanced version please stamp:

RecyclerView to create a rotation map (advanced version)