自定义Banner

作者: 夜沐下的星雨 | 来源:发表于2020-08-17 11:27 被阅读0次

    Banner 要实现的功能

    1.创建Banner (自定义Banner)
    2.创建IBannerData 接口
    3.创建BannerAdapter (适配器)
    4.创建Indicator 接口 (定义指示器要实现的方法)
    5.创建CircleIndicator (自定义指示器)
    6.创建ScrollSpeedManger(改变LinearLayoutManager的切换速度)

    1.创建IBannerData 接口:

    创建契约类:通过接口回调的方式获取title 和url

    public interface IBannerData {
        String getUrl();
        String getTitle();
    }
    
    

    2.创建BannerAdapter(banner适配器)

    创建适配器:继承RecyclerView.Adapter 给ViewPager2添加item

    public class BannerAdapter extends RecyclerView.Adapter<BannerAdapter.ViewHolder> {
        private static int mCount =0;
    
        private ArrayList<? extends IBannerData> mData;
    
        public BannerAdapter(ArrayList<? extends IBannerData> mData) {
            this.mData = mData;
        }
    
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            ImageView imageView = new ImageView(parent.getContext());
            imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            imageView.setTag(mCount);
            return new ViewHolder(imageView);
        }
    
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    
    
            position=position%mData.size();
    
            if (position==0){
                holder.setData(R.drawable.ee);
            }else if (position==1){
                holder.setData(R.drawable.dd);
            }else if (position==2){
                holder.setData(R.drawable.ff);
            }else if (position==3){
                holder.setData(R.drawable.gg);
            }
        }
    
        @Override
        public int getItemCount() {
            return mData==null?0:Integer.MAX_VALUE;
        }
    
        public class ViewHolder extends RecyclerView.ViewHolder {
            public ViewHolder(@NonNull View itemView) {
                super(itemView);
            }
            private void setData(int id){
                itemView.setBackgroundResource(id);
            }
        }
    }
    
    

    3.创建Banner(自定义banner)

    1.首先创建类继承ConstraintLayout (约束布局)
    2.通过new 的方式得到控件放到onFinishInflate 方法中。
    3.使用ConstraintSet 的对象将得到的控件克隆(clone)到父布局(ConstraintLayout )上。连接(connect)约束条件 ,并且设置控件的宽和高,适用于(applyTo)ConstraintLayout 布局中。至此完成了控件的创建。
    4.将dp 转换成px 应用于控件的高度 或与父容器的距离。

    public class Banner extends ConstraintLayout {
       private static final int DEFAULT_INTERVAL = 3000;//时间间隔
       private static final int DEFAULT_TIME = 3000;//时间间隔
        private ViewPager2 viewPager2;
        private TextView title;
        private Indicator mIndicator;
        private static int mIds=0x1000;//变量
        private ArrayList<? extends IBannerData> mData;//适配器使用
    
    
    
        private int mIndicatorEndMargin;//指示器端部边距
        private boolean isAutoLoop = true; // 是否自动循环
        private int mScrollTime ;// 轮播切换时间
        private int mInterval;  // 切换间隔时间
    
        private int mScrollMode;//切换模式
        private int mMarginTitleStart;//间距
        private int mTitleTextSize;//title 字体大小
        private int mTitleTextColor;//title 高度
        private int mTitleBgViewHeight;//title 的背景高度
        private int mIndicatorRadio;//半径
        private int mIndicatorSelectColor;//背景
        private int mIndicatorUnSelectColor;
    
        public Banner(Context context) {
            super(context);
        }
    
        public Banner(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public Banner(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
            initValue();
            initView();
        }
    
        private void initValue() {
            mIndicatorEndMargin= dip2px(15);
            mInterval=DEFAULT_INTERVAL;
            mScrollTime=DEFAULT_TIME;
        }
    
        public ViewPager2 getViewPager2() {
            return viewPager2;
        }
    
        public int getScrollTime() {
          return mScrollTime;
        }
    
        public Banner setScrollTime(int mScrollTime) {
            this.mScrollTime = mScrollTime;
            return this;
        }
    
        private void initView() {
            //添加一个viewPager2
            viewPager2 = new ViewPager2(getContext());
            //创建id
            viewPager2.setId(mIds++);
            //view Page2 监听
            viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
                @Override
                public void onPageSelected(int position) {
    
                    title.setText(mData.get(position % mData.size()).getTitle());
                    mIndicator.setCurrent(position % mData.size());
                }
            });
            //添加
            addView(viewPager2);
            //创建约束集
            ConstraintSet constraintSet = new ConstraintSet();
            //克隆约束集
            constraintSet.clone(this);
            constraintSet.connect(viewPager2.getId(),ConstraintSet.START,ConstraintSet.PARENT_ID,ConstraintSet.START);
            constraintSet.connect(viewPager2.getId(),ConstraintSet.END,ConstraintSet.PARENT_ID,ConstraintSet.END);
            constraintSet.connect(viewPager2.getId(),ConstraintSet.BOTTOM,ConstraintSet.PARENT_ID,ConstraintSet.BOTTOM);
            constraintSet.connect(viewPager2.getId(),ConstraintSet.TOP,ConstraintSet.PARENT_ID,ConstraintSet.TOP);
    
            constraintSet.constrainWidth(viewPager2.getId(),ConstraintSet.MATCH_CONSTRAINT);
            constraintSet.constrainHeight(viewPager2.getId(),ConstraintSet.MATCH_CONSTRAINT);
    
            //添加一个title 半透明背景
            ImageView background = new ImageView(getContext());
            background.setBackgroundColor(Color.parseColor("#40000000"));
            background.setId(mIds++);
            addView(background);
            constraintSet.connect(background.getId(),ConstraintSet.START,ConstraintSet.PARENT_ID,ConstraintSet.START);
            constraintSet.connect(background.getId(),ConstraintSet.END,ConstraintSet.PARENT_ID,ConstraintSet.END);
            constraintSet.connect(background.getId(),ConstraintSet.BOTTOM,ConstraintSet.PARENT_ID,ConstraintSet.BOTTOM);
            constraintSet.constrainWidth(background.getId(),ConstraintSet.MATCH_CONSTRAINT);
            constraintSet.constrainHeight(background.getId(),dip2px(30));
    
    
    
    
    
            //添加一个圆点容器
            mIndicator=new CircleIndicator(getContext());
            mIndicator.setRadio(10);
            mIndicator.setMargin(10);
            mIndicator.setSelectColor(Color.BLACK);
            mIndicator.setUnSelectColor(Color.WHITE);
            mIndicator.setId(mIds++);
            addView((View) mIndicator);
            constraintSet.connect(mIndicator.getId(),ConstraintSet.END,ConstraintSet.PARENT_ID,ConstraintSet.END,mIndicatorEndMargin);
            constraintSet.connect(mIndicator.getId(),ConstraintSet.BOTTOM,background.getId(),ConstraintSet.BOTTOM);
            constraintSet.connect(mIndicator.getId(),ConstraintSet.TOP,background.getId(),ConstraintSet.TOP);
            constraintSet.constrainWidth(mIndicator.getId(),ConstraintSet.MATCH_CONSTRAINT);
            constraintSet.constrainHeight(mIndicator.getId(),ConstraintSet.MATCH_CONSTRAINT);
    
    
    
            //添加一个title
            title = new TextView(getContext());
            title.setId(mIds++);
            title.setTextColor(Color.WHITE);
            title.setEllipsize(TextUtils.TruncateAt.MARQUEE);
            title.setSelected(true);
            title.setSingleLine(true);
            title.setMarqueeRepeatLimit(-1);
    
            addView(title);
            constraintSet.connect(title.getId(),ConstraintSet.START,ConstraintSet.PARENT_ID,ConstraintSet.START);
            constraintSet.connect(title.getId(),ConstraintSet.END,mIndicator.getId(),ConstraintSet.END,mIndicatorEndMargin);
            constraintSet.connect(title.getId(),ConstraintSet.BOTTOM,background.getId(),ConstraintSet.BOTTOM);
            constraintSet.connect(title.getId(),ConstraintSet.TOP,background.getId(),ConstraintSet.TOP);
            constraintSet.constrainWidth(title.getId(),ConstraintSet.MATCH_CONSTRAINT);
            constraintSet.constrainHeight(title.getId(),ConstraintSet.MATCH_CONSTRAINT);
    
            constraintSet.applyTo(this);
        }
        //触摸停止  dispatchTouchEvent
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
    
            switch (ev.getAction()){
                case MotionEvent.ACTION_DOWN:{
                    stopLoop();
                    break;
                }
                case MotionEvent.ACTION_UP:{
                    startLoop();
                }
            }
            return super.dispatchTouchEvent(ev);
        }
    
        public void setData(ArrayList<? extends IBannerData> bannerData){
            mData = bannerData;
            viewPager2.setAdapter(new BannerAdapter(bannerData));
            viewPager2.setUserInputEnabled(true);
            //viewPager2.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);//横向
            viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);//竖向
            ScrollSpeedManger.reflectLayoutManager(this);
            //取中间数来作为起始位置
            int index = (Integer.MAX_VALUE / 2) - (Integer.MAX_VALUE / 2 % bannerData.size());
            viewPager2.setCurrentItem(index,false);
    
            mIndicator.setCount(bannerData.size());
            mIndicator.setCurrent(index % mData.size());
            mIndicator.setCurrent(index%mData.size());
        }
        //事件分发  的可见性改变   如果能见度为 可见 就开始启动循环   否则就暂停循环   返回销毁
        @Override
        protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
            super.onVisibilityChanged(changedView, visibility);
            if(visibility == VISIBLE){
                startLoop();
            }else{
                stopLoop();
            }
        }
    
    
        private Runnable mLoopTask = new Runnable() {//创建多线程
            @Override
            public void run() {
                //获取当前项目item
                int currentItem = viewPager2.getCurrentItem();
                //给当前项目  传入item .和 smoothScroll  是否平滑滚动
                viewPager2.setCurrentItem(++currentItem, true);
                //getHandler()使用PostDelayed方法,切换间隔时间后调用此Runnable对象
                getHandler().postDelayed(mLoopTask,mInterval);
            }
        };
    
        private void startLoop(){
            if (isAutoLoop&&mData.size()>0&&mData!=null){
                getHandler().postDelayed(mLoopTask,mInterval);
            }
        }
        private void stopLoop(){
            //删除回调mLoopTask
            getHandler().removeCallbacks(mLoopTask);
        }
            //dp  转px
        public  int dip2px(float dpValue) {
            final float scale = getContext().getResources().getDisplayMetrics().density;
            return (int) (dpValue * scale + 0.5f);
        }
    
    }
    

    4.创建Indicator 接口 (定义指示器要实现的方法)

    //创建接口指示符    指示器的接口
    public interface Indicator {
        void setRadio(int radio);
        //数量
        void setCount(int count);
        void setCurrent(int index);
        void setUnSelectColor(int color);
        void setSelectColor(int color);
        void setMargin(int margin);
        void setId(int id);
        int getId();
    }
    

    5.创建CircleIndicator (自定义指示器)

    
    public class CircleIndicator extends View implements Indicator{
    
        private static final int MAX_COUNT = 10;//最大显示个数
        private int mCurrentIndex;
        private int unSelectColor;//颜色
        private int selectColor;//颜色
        private int mRadio;//半径
        private int mCount;// 最终显示个数
        private int mCurrent; // 实际个数
        private int mMargin;//间距
        private int mHeight;
        private int mWidth;
        private Paint mPaint;
    
    
        public CircleIndicator(Context context) {
            super(context);
            initPain();
        }
    
        public CircleIndicator(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            initPain();
        }
    
        public CircleIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initPain();
        }
    
        //创建画笔
        private void initPain(){
            mPaint = new Paint();
            mPaint.setAntiAlias(true);//图片去锯齿
            mPaint.setStyle(Paint.Style.FILL);//填充样式
            mPaint.setColor(Color.WHITE);//默认白色
        }
        //计算圆点的高和宽
        private void calculation(){
            //获取高度
            mHeight = mRadio * 2;
            //最终显示个数    如果定了显示个数,或最大显示个数,找最小的为最终显示个数。
            mCount = Math.min(mCurrent,MAX_COUNT);
            //获取宽度
            mWidth = (mCount * mRadio * 2) + (mCount - 1) * mMargin;
            invalidate(); // 刷新页面,重新onMeasure onLayout,onDraw
        }
        //测量
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            //测量的尺寸为  规格  宽  mWidth   高 mHeight
            setMeasuredDimension(MeasureSpec.makeMeasureSpec(mWidth,MeasureSpec.EXACTLY),MeasureSpec.makeMeasureSpec(mHeight,MeasureSpec.EXACTLY));
        }
        //绘制
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //显示的个数 for循环    绘制圆点
            for (int i = 0; i < mCount; i++) {
                if (i==mCurrentIndex){
                   mPaint.setColor(selectColor);
                }else{
                    mPaint.setColor(unSelectColor);
                }
                //宽,高,半径,画笔
                canvas.drawCircle((i*(mRadio*2)+(i*mMargin)+mRadio),mRadio,mRadio,mPaint);
            }
        }
    
        @Override
        public void setRadio(int radio) {
            mRadio =radio;
        }
        @Override
        public void setMargin(int margin) {
            mMargin=margin;
        }
        @Override
        public void setCount(int count) {
            //如果实际个数不等于显示的个数就复值 并计算圆点容器的高和宽
            if (mCurrent!=count){
                mCurrent=count;
                calculation();
            }
    
        }
    
        @Override
        public void setCurrent(int index) {
            //传入的数与mCurrentIndex 不同复值,并刷新页面
            if (mCurrentIndex!=index){
                mCurrentIndex=index;
                invalidate(); // 刷新页面,重新onMeasure onLayout,onDraw
            }
    
        }
    
        @Override
        public void setUnSelectColor(int color) {
            unSelectColor=color;
        }
    
        @Override
        public void setSelectColor(int color) {
            selectColor=color;
        }
    
    
    }
    
    

    6.创建ScrollSpeedManger(改变LinearLayoutManager的切换速度)

    要在Banner 中创建get方法 获取ViewPager2

    
    /**
     * 改变LinearLayoutManager的切换速度
     */
    public class ScrollSpeedManger extends LinearLayoutManager {
        private Banner banner;
    
        public ScrollSpeedManger(Banner banner, LinearLayoutManager linearLayoutManager) {
            super(banner.getContext(), linearLayoutManager.getOrientation(), false);
            this.banner = banner;
        }
    
        @Override
        public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
            LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
                @Override
                protected int calculateTimeForDeceleration(int dx) {
                    return banner.getScrollTime();
                }
            };
            linearSmoothScroller.setTargetPosition(position);
            startSmoothScroll(linearSmoothScroller);
        }
    
        public static void reflectLayoutManager(Banner banner) {
            if (banner.getScrollTime() < 100) return;
            try {
                ViewPager2 viewPager2 = banner.getViewPager2();
                RecyclerView recyclerView = (RecyclerView) viewPager2.getChildAt(0);
                recyclerView.setOverScrollMode(RecyclerView.OVER_SCROLL_NEVER);
    
                ScrollSpeedManger speedManger = new ScrollSpeedManger(banner, (LinearLayoutManager) recyclerView.getLayoutManager());
                recyclerView.setLayoutManager(speedManger);
    
    
                Field LayoutMangerField = ViewPager2.class.getDeclaredField("mLayoutManager");
                LayoutMangerField.setAccessible(true);
                LayoutMangerField.set(viewPager2, speedManger);
    
                Field pageTransformerAdapterField = ViewPager2.class.getDeclaredField("mPageTransformerAdapter");
                pageTransformerAdapterField.setAccessible(true);
                Object mPageTransformerAdapter = pageTransformerAdapterField.get(viewPager2);
                if (mPageTransformerAdapter != null) {
                    Class<?> aClass = mPageTransformerAdapter.getClass();
                    Field layoutManager = aClass.getDeclaredField("mLayoutManager");
                    layoutManager.setAccessible(true);
                    layoutManager.set(mPageTransformerAdapter, speedManger);
                }
                Field scrollEventAdapterField = ViewPager2.class.getDeclaredField("mScrollEventAdapter");
                scrollEventAdapterField.setAccessible(true);
                Object mScrollEventAdapter = scrollEventAdapterField.get(viewPager2);
                if (mScrollEventAdapter != null) {
                    Class<?> aClass = mScrollEventAdapter.getClass();
                    Field layoutManager = aClass.getDeclaredField("mLayoutManager");
                    layoutManager.setAccessible(true);
                    layoutManager.set(mScrollEventAdapter, speedManger);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    
    

    相关文章

      网友评论

        本文标题:自定义Banner

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