自定义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