美文网首页
一个基于阿里Vlayout的Banner

一个基于阿里Vlayout的Banner

作者: 835fd398e0dd | 来源:发表于2020-01-15 19:25 被阅读0次

A banner demo is based on vlayout


一个基于阿里RecyclerView框架Vlayout的Banner,可实现自动轮播,滑动暂停轮播,底部indicator指示器。

大体思路:把ViewPager用一个ViewHolder包起来,做成一个size为1的adapter放在RecyclerView中。使用Handler处理轮播,在ViewPager的监听器中改变底部indicator,以及控制滑动暂定轮播--当ScrollState为SCROLL_STATE_DRAGGING的时候把定时任务取消,下一次ScrollState为SCROLL_STATE_IDLE的时候再开启定时任务。ViewPager的PagerAdapter使用Vlayout的RecyclablePagerAdapter。由于RecyclerView的Adapter 的Item在滑出屏幕再滑入屏幕的时候onBindViewHolder会重复调用,如果不加以控制的化就会每次onBindViewHolder调用都初始化一遍ViewPager,导致banner滑回来的时候就跳到了第一张,其实banner只需要初始化一次就够了,为了解决这个问题,再onBindViewHolder的时候通过标志位判断,如果未初始化才走初始化过程,当数据变化时,改变标志位重新初始化banner。

两个ViewHolder

①BannerViewHolder:外层存放ViewPager和指示器LinearLayout的viewHolder(itemCount = 1)

    static class BannerViewHolder extends RecyclerView.ViewHolder {

        private ViewPager viewPager;

        private LinearLayout pointLl;

        BannerViewHolder(@NonNull View itemView) {

            super(itemView);

            viewPager = itemView.findViewById(R.id.banner_pager);

            pointLl = itemView.findViewById(R.id.banner_point);

        }

    }

②BannerInnerViewHolder: 内层存放轮播图的ViewHolder

    static class BannerInnerViewHolder extends RecyclerView.ViewHolder {

        private ImageView imageView;

        BannerInnerViewHolder(@NonNull View itemView) {

            super(itemView);

            imageView = itemView.findViewById(R.id.iv_content);

        }

    }

onCreateViewHolder根据不同的itemType返回不同的ViewHolder

    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int type) {

        if (type == BANNER_OUTER_TYPE) {

            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.banner_viewpager, viewGroup, false);

            return new BannerViewHolder(view);

        } else {

            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.banner_inner, viewGroup, false);

            return new BannerInnerViewHolder(view);

        }

    }

继承Vlayout RecyclablePagerAdapter的PagerAdater 为了让banner无限滑动这里把ViewPager的count设置为MAX_VALUE,并在viewPager初始化时把CurrentItem设置为一个中间的的数

        @Override

        public int getCount() {

            if (bannerInfoList.size() == 1) {

                return 1;

            }

            return Integer.MAX_VALUE;

        }

        @Override

        public void onBindViewHolder(BannerInnerViewHolder viewHolder, int position) {

            viewHolder.imageView.setImageDrawable(bannerInfoList.get(position % bannerInfoList.size()).drawable);

        }

        @Override

        public int getItemViewType(int position) {

            return BANNER_INNER_TYPE;

        }

初始化indicator的pointList,initPointViewList,根据banner数量添加ImageView圆点。

在外层Adapter的onBindViewHolder中初始化ViewPager,设置mViewpager的CurrentItem, 把pointList添加到在线性布局中,并改变初始化标志位

@Override

    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {

        if (holder instanceof BannerViewHolder && !init) {

            BannerViewHolder viewHolder = (BannerViewHolder) holder;

            mViewPager = viewHolder.viewPager;

            mViewPager.setAdapter(new PagerAdapter(mContext, this, mViewPool, bannerInfoList));

            if (bannerInfoList.size() == 1) {

                mViewPager.setCurrentItem(0);

            } else {

                mViewPager.setCurrentItem(bannerInfoList.size() * 100);

            }

            LinearLayout mPointRealContainerLl = viewHolder.pointLl;

            mPointRealContainerLl.removeAllViews();

            for (ImageView pointItem : pointList) {

                mPointRealContainerLl.addView(pointItem);

            }

            init = true;

        }

    }

在ViewPager的PageChangeListener中主要时①在图片切换时改变指示器②在拖动时removeHandlerMessage, 在拖动完成变成idle状态时候再开启定时任务sendEmptyMessageDelayed,每次被用户拖动的时候state就变成DRAGGING,在放开归位之后就变成IDLE ,看官方关于ViewPager.STATE 的解释

    /**

    * Indicates that the pager is in an idle, settled state. The current page

    * is fully in view and no animation is in progress.

    */

    public static final int SCROLL_STATE_IDLE = 0;

    /**

    * Indicates that the pager is currently being dragged by the user.

    */

    public static final int SCROLL_STATE_DRAGGING = 1;

    /**

    * Indicates that the pager is in the process of settling to a final position.

    */

    public static final int SCROLL_STATE_SETTLING = 2;

我对三个状态的理解为

SCROLL_STATE_IDLE:此时处于归位、呆滞的状态,没有动画,完全展示

SCROLL_STATE_DRAGGING:被用户拖动

SCROLL_STATE_SETTLING:在过渡到另外一个position的过程中

        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

                boolean dragging =  false;

                @Override

                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

                }

                @Override

                public void onPageSelected(int position) {

                    //indicator

                    for (int i = 0; i < pointList.size() && pointList.size() != 1; i++) {

                        ImageView point = pointList.get(i);

                        if (i == position % bannerInfoList.size()) {

                            point.setImageResource(R.drawable.banner_indicator_rec_selected);

                            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(dp2px(mContext, 10), dp2px(mContext, 4));

                            lp.setMargins(dp2px(mContext, 3), 0, dp2px(mContext, 3), 0);

                            point.setLayoutParams(lp);

                        } else {

                            point.setImageResource(R.drawable.banner_indicator_rec_normal);

                            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(dp2px(mContext, 4), dp2px(mContext, 4));

                            lp.setMargins(dp2px(mContext, 3), 0, dp2px(mContext, 3), 0);

                            point.setLayoutParams(lp);

                        }

                    }

                }

                @Override

                public void onPageScrollStateChanged(int state) {

                    /**

                    * 当dragging的时候就把定时任务取消

                    * 下一次idle的时候再开启定时任务

                    */

                    switch (state) {

                        case ViewPager.SCROLL_STATE_IDLE:

                            Log.d(TAG, "onPageScrollStateChanged: SCROLL_STATE_IDLE" );

                            if (dragging) {

                                sendEmptyMessageDelayed();

                                dragging = false;

                            }

                            break;

                        case ViewPager.SCROLL_STATE_DRAGGING:

                            Log.d(TAG, "onPageScrollStateChanged: SCROLL_STATE_DRAGGING" );

                            dragging = true;

                            removeHandlerMessage();

                            break;

                        default:

                            break;

                    }

                }

            });

Handler轮询,改变CurrentItem,并延迟6s(banner跳转间隔)再发message,使用hashCode是为了防止实例化多个 BannerAdapter导致一个banner处理其他banner发来的消息

mHandler = new Handler(Looper.getMainLooper()) {

            @Override

            public void handleMessage(Message msg) {

                super.handleMessage(msg);

                if (msg.what == hashCode) {

                    if (mViewPager != null && BannerAdapter.this.bannerInfoList.size() != 1) {

                        mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1);

                    }

                    sendEmptyMessageDelayed(hashCode, 6000);

                }

            }

        };

    private void removeHandlerMessage() {

        if (mHandler != null) {

            mHandler.removeMessages(hashCode);

        }

    }

    private void sendEmptyMessageDelayed() {

        if (mHandler != null) {

            mHandler.sendEmptyMessageDelayed(hashCode, 6000);

        }

    }

当banner数据改变例如网络数据刷新需要重新初始化banner

    public void setBannerInfoList(List<BannerInfo> bannerInfoList) {

        this.bannerInfoList = bannerInfoList;

        init = false;

        notifyDataSetChanged();

    }

完整Demo地址:BannerDemo

相关文章

网友评论

      本文标题:一个基于阿里Vlayout的Banner

      本文链接:https://www.haomeiwen.com/subject/cyxxzctx.html