Android 最完善的自定义Banner轮播图之一,带给你最全面的体验

Android 最完善的自定义Banner轮播图之一,带给你最全面的体验(二)

Android 最完善的自定义Banner轮播图之一,带给你最全面的体验(三)

一.源码:看源码

支持无限循环轮播

支持圆形指示器

支持方形指示器

支持圆角方形指示器

支持修改轮播时间

支持自定义显示内容

支持指示器颜色大小修改 

支持图片监听跳转

支持触摸停止轮播动画

二.效果图:

 

 

记得添加依赖(阿里开源库): 

 //gradle
    api ('com.alibaba.android:ultraviewpager:1.0.7.7@aar') {
        transitive = true
    }

 

1.属性说明: 

 //指示器样式一 选中未选中都是圆点
    public static final int STYLE_CIRCLR_CIRCLE = 0;
    //指示器样式二 选中未选中都是方形
    public static final int STYLE_RECT_RECT = 1;
    //指示器样式三 选中方形,未选中圆点
    public static final int STYLE_CIRCLR_RECT = 2;

 

<declare-styleable name="Indicator">
        <!--未选中的指示器颜色-->
        <attr name="normal_color" format="reference|color" />
        <!--选中的指示器颜色-->
        <attr name="selected_color" format="reference|color" />
        <!--指示器每个item之间的间距-->
        <attr name="spacing" format="dimension" />
        <!--指示器排列方向-->
        <attr name="orientation" format="enum">
            <enum name="horizontal" value="0" />
            <enum name="vertical" value="1" />
        </attr>

        <!--指示器类型 命名规则:未选中样式_选中样式-->
        <attr name="style" format="enum">
            <!--都是圆点-->
            <enum name="circle_circle" value="0"/>
            <!--都是方形-->
            <enum name="rect_rect" value="1" />
            <!--未选中是圆点,选中是方形-->
            <enum name="circle_rect" value="2" />
        </attr>

        <!--都是圆点指示器半径大小-->
        <attr name="circle_circle_radius" format="dimension" />

        <!--都是方形指示器长度-->
        <attr name="rect_rect_itemWidth" format="dimension" />
        <!--都是方形指示器高度-->
        <attr name="rect_rect_itemHeight" format="dimension" />
        <!--都是方形指示器圆角-->
        <attr name="rect_rect_corner" format="dimension" />

        <!--circle_rect 模式圆点半径-->
        <attr name="circle_rect_radius" format="dimension" />
        <!--circle_rect 模式方形宽度-->
        <attr name="circle_rect_itemWidth" format="dimension" />
        <!--circle_rect 模式方形高度-->
        <attr name="circle_rect_itemHeight" format="dimension" />
        <!--circle_rect 模式方形圆角-->
        <attr name="circle_rect_corner" format="dimension" />

</declare-styleable>

共用属性

属性说明
normal_color未选中的指示器颜色
selected_color选中的指示器颜色
spacing指示器每个item之间的间距
orientation设置指示器排列方向,枚举类型,有horizontalvertical
style枚举类型,有如下几种类型

style样式说明

style说明
circle_circle圆点指示器,对应图中第三个指示器样式
rect_rect长条指示器,对应图中第二个指示器样式
circle_rect指示器选中是长条,未选中是圆点,对应图中第一个指示器样式

如果style设置为 circle_circle可设置以下属性:

属性说明
circle_circle_radius都是圆点指示器半径大小

如果style设置为 rect_rect可设置以下属性:

属性说明
rect_rect_itemWidth条形长度
rect_rect_itemHeight条形高度
rect_rect_corner条形圆角

如果style设置为 circle_rect可设置以下属性:

属性说明
circle_rect_radius未选中圆点半径
circle_rect_itemWidth选中条形长度
circle_rect_itemHeight选中条形高度
circle_rect_corner选中条形设置圆角

2.布局代码:

主布局

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="140dp">

            <androidx.viewpager.widget.ViewPager
                android:id="@+id/viewPager1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@android:color/darker_gray" />

            <com.example.mysgfceshicase.sgf.activity.hibanner.UIndicator
                android:id="@+id/indicator1"
                android:layout_width="6dp"
                android:layout_height="wrap_content"
                android:layout_gravity="left|center_vertical"
                android:layout_marginLeft="10dp"
                app:circle_rect_corner="3dp"
                app:circle_rect_itemHeight="16dp"
                app:circle_rect_itemWidth="3dp"
                app:circle_rect_radius="3dp"
                app:normal_color="#99ffffff"
                app:orientation="vertical"
                app:selected_color="#ffffff"
                app:spacing="6dp"
                app:style="circle_rect" />
        </FrameLayout>

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="160dp"
            android:layout_marginTop="10dp">

            <androidx.viewpager.widget.ViewPager
                android:id="@+id/viewPager2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@android:color/darker_gray" />

            <com.example.mysgfceshicase.sgf.activity.hibanner.UIndicator
                android:id="@+id/indicator2"
                android:layout_width="4dp"
                android:layout_height="wrap_content"
                android:layout_gravity="right|center_vertical"
                android:layout_marginRight="10dp"
                app:normal_color="#99ffffff"
                app:orientation="vertical"
                app:rect_rect_corner="3dp"
                app:rect_rect_itemHeight="16dp"
                app:rect_rect_itemWidth="3dp"
                app:selected_color="#ffffff"
                app:spacing="10dp"
                app:style="rect_rect" />
        </FrameLayout>

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="120dp"
            android:layout_marginTop="10dp">

            <androidx.viewpager.widget.ViewPager
                android:id="@+id/viewPager3"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@android:color/darker_gray" />

            <com.example.mysgfceshicase.sgf.activity.hibanner.UIndicator
                android:id="@+id/indicator3"
                android:layout_width="match_parent"
                android:layout_height="6dp"
                android:layout_gravity="bottom|center_horizontal"
                android:layout_marginBottom="10dp"
                app:circle_circle_radius="3dp"
                app:normal_color="#99ffffff"
                app:selected_color="#ffffff"
                app:spacing="10dp"
                app:style="circle_circle" />
        </FrameLayout>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="支持阿里开源库:UltraViewPager" />

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="120dp"
            android:layout_marginTop="10dp">

            <com.tmall.ultraviewpager.UltraViewPager
                android:id="@+id/ultra_viewpager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_centerInParent="true"
                android:background="@android:color/darker_gray"
                app:upv_autoscroll="3000"
                app:upv_infiniteloop="true" />

            <com.example.mysgfceshicase.sgf.activity.hibanner.UIndicator
                android:id="@+id/indicator4"
                android:layout_width="match_parent"
                android:layout_height="6dp"
                android:layout_gravity="bottom|center_horizontal"
                android:layout_marginBottom="10dp"
                app:circle_rect_corner="3dp"
                app:rect_rect_corner="3dp"
                app:circle_rect_itemHeight="4dp"
                app:circle_rect_itemWidth="20dp"
                app:circle_rect_radius="3dp"
                app:normal_color="#99ffffff"
                app:selected_color="#ffffff"
                app:spacing="10dp"
                app:style="rect_rect" />
        </FrameLayout>
    </LinearLayout>
</ScrollView>

适配器布局 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/im"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical"/>
    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="wrap_content"
        android:textColor="@color/blue"
        android:gravity="center_vertical"/>


</RelativeLayout>

 

3.主函数代码与适配器等:

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Toast;

import com.example.mysgfceshicase.R;
import com.example.mysgfceshicase.sgf.bean.MySgfBean;
import com.tmall.ultraviewpager.UltraViewPager;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.ViewConfigurationCompat;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

public class HiBannerActivity extends AppCompatActivity {

    private ViewPager mViewPager1, mViewPager2, mViewPager3;
    private DemoPagerAdapter mAdapter1, mAdapter2, mAdapter3,mAdapter4;

    private UltraViewPager mViewPager4;
    private UIndicator uIndicator1, uIndicator2, uIndicator3,uIndicator4;

    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hibanner);
        mViewPager1 = findViewById(R.id.viewPager1);
        mViewPager2 = findViewById(R.id.viewPager2);
        mViewPager3 = findViewById(R.id.viewPager3);
        mViewPager4 = findViewById(R.id.ultra_viewpager);

        uIndicator1 = findViewById(R.id.indicator1);
        uIndicator2 = findViewById(R.id.indicator2);
        uIndicator3 = findViewById(R.id.indicator3);
        uIndicator4 = findViewById(R.id.indicator4);


        mAdapter1 = new DemoPagerAdapter(getList());
        mViewPager1.setAdapter(mAdapter1);
        uIndicator1.attachToViewPager(mViewPager1);

        mAdapter2 = new DemoPagerAdapter(getList());
        mViewPager2.setAdapter(mAdapter2);
        uIndicator2.attachToViewPager(mViewPager2);

        mAdapter3 = new DemoPagerAdapter(getList());
        mViewPager3.setAdapter(mAdapter3);
        uIndicator3.attachToViewPager(mViewPager3);

//        mAdapter4 = new DemoPagerAdapter(getList());
        HiPagerAdapter mAdapter5 = new HiPagerAdapter(this,getMyList());
        mViewPager4.setAdapter(mAdapter5);
        uIndicator4.attachToViewPager(mViewPager4.getViewPager());

//        ViewConfiguration configuration = ViewConfiguration.get(this);
//        int mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);


//        mViewPager4.setOnTouchListener(new View.OnTouchListener() {
//            int touchFlag = 0;
//            float x = 0, y = 0;
//
//            @Override
//            public boolean onTouch(View v, MotionEvent event) {
//                switch (event.getAction()) {
//                    case MotionEvent.ACTION_DOWN:
//                        touchFlag = 0;
//                        x = event.getX();
//                        y = event.getY();
//                        break;
//                    case MotionEvent.ACTION_MOVE:
//                        float xDiff = Math.abs(event.getX() - x);
//                        float yDiff = Math.abs(event.getY() - y);
//                        if (xDiff < mTouchSlop && xDiff >= yDiff)
//                            touchFlag = 0;
//                        else
//                            touchFlag = -1;
//                        break;
//                    case MotionEvent.ACTION_UP:
//                        if (touchFlag == 0) {
//                            int currentItem = mViewPager4.getCurrentItem();
//                            Toast.makeText(HiBannerActivity.this,""+ currentItem,Toast.LENGTH_SHORT).show();
                            Intent it = new Intent();
                            it.setClass(getActivity(), NewsDetailsActivity.class);
                            it.putExtra("story_id", topStories.get(currentItem).getId());
                            startActivity(it);
//                        }
//                        break;
//                }
//                return false;
//            }
//        });

    }
    public List<MySgfBean> getMyList() {
        List<MySgfBean> list = new ArrayList<>();

        for (int i = 0; i < 5; i++) {

            list.add(new MySgfBean(R.drawable.timg,"KING"+i));
        }
        return list;
    }

    public List<View> getList() {
        List<View> list = new ArrayList<>();
        Random rm = new Random();
        for (int i = 0; i < 5; i++) {
            int ranColor = 0xff000000 | rm.nextInt(0x00ffffff);
            list.add(generateView(ranColor));
        }
        return list;
    }

    public View generateView(int color) {
        View tv = new View(this);
        ViewPager.LayoutParams lp = new ViewPager.LayoutParams();
        lp.width = ViewPager.LayoutParams.MATCH_PARENT;
        lp.height = ViewPager.LayoutParams.MATCH_PARENT;
        tv.setBackgroundColor(color);
        tv.setLayoutParams(lp);

        return tv;
    }

    public class DemoPagerAdapter extends PagerAdapter {
        private List<View> views;

        public DemoPagerAdapter(List<View> views) {
            this.views = views;
        }

        @Override
        public int getCount() {
            return views.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            View view = views.get(position);
            container.addView(view);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(HiBannerActivity.this,""+ position,Toast.LENGTH_SHORT).show();
                }
            });
            return view;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(views.get(position));
        }
    }

}
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
import com.example.mysgfceshicase.R;
import com.example.mysgfceshicase.sgf.bean.MySgfBean;

import java.util.List;
import java.util.Random;

import androidx.viewpager.widget.PagerAdapter;

/**
 * 版权:KING公司 版权所有
 *
 * @author KING
 * 版本:1.0
 * 创建日期:2019/6/6
 * 描述:---
 */
public class HiPagerAdapter extends PagerAdapter {
    //上下文
    private Context mContext;
    //数据
    private List<MySgfBean> mData;

    /**
     * 构造函数
     * 初始化上下文和数据
     *
     * @param context
     * @param list
     */
    public HiPagerAdapter(Context context, List<MySgfBean> list) {
        mContext = context;
        mData = list;
    }

    /**
     * 返回要滑动的VIew的个数
     *
     * @return
     */
    @Override
    public int getCount() {
        return mData.size();
    }

    /**
     * 1.将当前视图添加到container中
     * 2.返回当前View
     *
     * @param container
     * @param position
     * @return
     */
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view = View.inflate(mContext, R.layout.view_vp_item, null);
        TextView tv = view.findViewById(R.id.tv);
        ImageView im = view.findViewById(R.id.im);
        tv.setText(mData.get(position).getContext());
        //Glide 4.6以上写法
        RequestOptions options = new RequestOptions()
                .centerCrop()
                .placeholder(R.mipmap.bg_mine)
                .dontAnimate()
                .diskCacheStrategy(DiskCacheStrategy.ALL);
        Glide.with(mContext)
                .load(mData.get(position).getImg())
                .apply(options)
                .into(im);
        im.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(mContext,""+ position,Toast.LENGTH_SHORT).show();
            }
        });
        Random random = new Random();
        int ranColor = 0xff000000 | random.nextInt(0x00ffffff);
        tv.setBackgroundColor(ranColor);
        container.addView(view);
        return view;
    }

    /**
     * 从当前container中删除指定位置(position)的View
     *
     * @param container
     * @param position
     * @param object
     */
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        // super.destroyItem(container,position,object); 这一句要删除,否则报错
        container.removeView((View) object);
    }

    /**
     * 确定页视图是否与特定键对象关联
     *
     * @param view
     * @param object
     * @return
     */
    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }
}

 自定义指示器类:


import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

import com.example.mysgfceshicase.R;
import com.tmall.ultraviewpager.UltraViewPagerAdapter;

import androidx.annotation.Nullable;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;


/**
 * @Description: 通用ViewPager指示器
 */
public class UIndicator extends View implements ViewPager.OnPageChangeListener {

    private static final String TAG = "UIndicator";

    //指示器样式一 选中未选中都是圆点
    public static final int STYLE_CIRCLR_CIRCLE = 0;
    //指示器样式二 选中未选中都是方形
    public static final int STYLE_RECT_RECT = 1;
    //指示器样式三 选中方形,未选中圆点
    public static final int STYLE_CIRCLR_RECT = 2;

    //横向排列
    public static final int HORIZONTAL = 0;
    //纵向排列
    public static final int VERTICAL = 1;

    private Context mContext;

    //指示器之间的间距
    private int spacing;
    //指示器排列方向
    private int orientation = HORIZONTAL;
    //选中与为选中的颜色
    private ColorStateList selectedColor, normalColor;

    //指示器样式,默认都是圆点
    private int mStyle = STYLE_CIRCLR_CIRCLE;

    //样式一 圆点半径大小
    private int circleCircleRadius = 0;

    //样式二 方形大小及圆角
    private int rectRectItemWidth = 0, rectRectItemHeight = 0, rectRectCorner = 0;

    //样式三 选中的方形大小及圆角
    private int circleRectItemWidth = 0, circleRectItemHeight = 0, circleRectCorner = 0;
    //样式三 未选中的圆点半径
    private int circleRectRadius = 0;

    //画笔
    private Paint normalPaint, selectedPaint;

    //指示器item的区域
    private RectF mRectF;
    //指示器大小
    private int width, height;
    //指示器item个数
    private int itemCount = 0;
    //当前选中的位置
    private int selection = 0;

    private ViewPager viewPager;

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

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

    public UIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        init(attrs);
        intPaint();
        checkItemCount();
    }

    /**
     * 加载自定义属性
     */
    private void init(AttributeSet attrs) {
        // 加载自定义属性集合
        TypedArray ta = mContext.obtainStyledAttributes(attrs, R.styleable.Indicator);
        // 第二个参数是默认设置颜色
        selectedColor = ta.getColorStateList(R.styleable.Indicator_selected_color);
        normalColor = ta.getColorStateList(R.styleable.Indicator_normal_color);
        spacing = ta.getDimensionPixelSize(R.styleable.Indicator_spacing, dip2px(6));
        orientation = ta.getInt(R.styleable.Indicator_orientation, HORIZONTAL);
        mStyle = ta.getInt(R.styleable.Indicator_style, STYLE_CIRCLR_CIRCLE);

        circleCircleRadius = ta.getDimensionPixelSize(R.styleable.Indicator_circle_circle_radius, dip2px(3));

        rectRectCorner = ta.getDimensionPixelSize(R.styleable.Indicator_rect_rect_corner, 0);
        rectRectItemHeight = ta.getDimensionPixelSize(R.styleable.Indicator_rect_rect_itemHeight, dip2px(3));
        rectRectItemWidth = ta.getDimensionPixelSize(R.styleable.Indicator_rect_rect_itemWidth, dip2px(15));

        circleRectCorner = ta.getDimensionPixelSize(R.styleable.Indicator_circle_rect_corner, 0);
        circleRectRadius = ta.getDimensionPixelSize(R.styleable.Indicator_circle_rect_radius, dip2px(3));//3
        circleRectItemHeight = ta.getDimensionPixelSize(R.styleable.Indicator_circle_rect_itemHeight, dip2px(3));
        circleRectItemWidth = ta.getDimensionPixelSize(R.styleable.Indicator_circle_rect_itemWidth, dip2px(15));

        // 解析后释放资源
        ta.recycle();
    }

    private void intPaint() {
        normalPaint = new Paint();
        normalPaint.setStyle(Paint.Style.FILL);
        normalPaint.setAntiAlias(true);
        normalPaint.setColor(normalColor == null ? Color.GRAY : normalColor.getDefaultColor());

        selectedPaint = new Paint();
        selectedPaint.setStyle(Paint.Style.FILL);
        selectedPaint.setAntiAlias(true);
        selectedPaint.setColor(selectedColor == null ? Color.RED : selectedColor.getDefaultColor());

        mRectF = new RectF();
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        switch (mStyle) {
            case STYLE_CIRCLR_CIRCLE:
                if (orientation == HORIZONTAL){
                    width = 2 * circleCircleRadius * itemCount + (itemCount - 1) * spacing;
                    height = Math.max(heightSize, 2 * circleCircleRadius);
                } else {
                    height = 2 * circleCircleRadius * itemCount + (itemCount - 1) * spacing;
                    width = Math.max(widthSize, 2 * circleCircleRadius);
                }
                break;
            case STYLE_RECT_RECT:
                if (orientation == HORIZONTAL){
                    width = rectRectItemWidth * itemCount + (itemCount - 1) * spacing;
                    height = Math.max(heightSize, rectRectItemHeight);
                } else {
                    height = rectRectItemHeight * itemCount + (itemCount - 1) * spacing;
                    width = Math.max(widthSize, rectRectItemWidth);
                }
                break;
            case STYLE_CIRCLR_RECT:
                if (orientation == HORIZONTAL){
                    int normalItemWidth = circleRectRadius * 2;
                    width = (itemCount - 1) * normalItemWidth + circleRectItemWidth + (itemCount - 1) * spacing;
                    int tempHeight = Math.max(circleRectItemHeight, circleRectRadius * 2);
                    height = Math.max(heightSize, tempHeight);
                } else {
                    int normalItemHeight = circleRectRadius * 2;
                    height = (itemCount - 1) * normalItemHeight + circleRectItemHeight + (itemCount - 1) * spacing;
                    int tempWidth = Math.max(circleRectItemWidth, circleRectRadius * 2);
                    width = Math.max(widthSize, tempWidth);
                }

                break;
        }

        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (orientation == HORIZONTAL) {
            switch (mStyle) {

                case STYLE_CIRCLR_CIRCLE:
                    float cy = height / 2;
                    for (int i = 0; i < itemCount; i++) {
                        int cx = (i + 1) * circleCircleRadius + i * spacing;
                        //全部绘制圆点,画笔的区别
                        canvas.drawCircle(cx, cy, circleCircleRadius, i == selection ? selectedPaint : normalPaint);
                    }
                    break;

                case STYLE_RECT_RECT:
                    for (int i = 0; i < itemCount; i++) {
                        int left = i * rectRectItemWidth + i * spacing;
                        mRectF.set(left, 0, left + rectRectItemWidth, rectRectItemHeight);
                        //全部绘制圆角矩形,画笔的区别
                        canvas.drawRoundRect(mRectF, rectRectCorner, rectRectCorner, i == selection ? selectedPaint : normalPaint);
                    }
                    break;

                case STYLE_CIRCLR_RECT:
                    for (int i = 0; i < itemCount; i++) {
                        int left = selection * (circleRectRadius * 2 + spacing);
                        int top;
                        if (selection == i) {
                            //选中的绘制圆角矩形
                            top = (height - circleRectItemHeight) / 2;
                            mRectF.set(left, top, left + circleRectItemWidth, circleRectItemHeight + top);
                            canvas.drawRoundRect(mRectF, circleRectCorner, circleRectCorner, selectedPaint);
                        } else {
                            //未选中的绘制圆点,距离需要判断position在选中的左边或者右边,从而确定cx
                            top = (height - circleRectRadius * 2) / 2;
                            int cx = 0;
                            float cy1 = circleRectRadius + top;
                            if (selection < i) {
                                cx = (i - 1) * circleRectRadius * 2 + i * spacing + circleRectItemWidth + circleRectRadius;
                            } else {
                                cx = i * (circleRectRadius * 2) + i * spacing + circleRectRadius;
                            }
                            canvas.drawCircle(cx, cy1, circleRectRadius, normalPaint);
                        }

                    }
                    break;
            }
        } else {
            switch (mStyle) {

                case STYLE_CIRCLR_CIRCLE:
                    float cx = width / 2;
                    for (int i = 0; i < itemCount; i++) {
                        int cy = i * (circleCircleRadius * 2 + spacing)+ circleCircleRadius;
                        //全部绘制圆点,画笔的区别
                        canvas.drawCircle(cx, cy, circleCircleRadius, i == selection ? selectedPaint : normalPaint);
                    }
                    break;

                case STYLE_RECT_RECT:
                    for (int i = 0; i < itemCount; i++) {
                        int top = i * rectRectItemHeight + i * spacing;
                        int left = (width - rectRectItemWidth) / 2;
                        mRectF.set(left, top, left + rectRectItemWidth, top + rectRectItemHeight);
                        //全部绘制圆角矩形,画笔的区别
                        canvas.drawRoundRect(mRectF, rectRectCorner, rectRectCorner, i == selection ? selectedPaint : normalPaint);
                    }
                    break;

                case STYLE_CIRCLR_RECT:
                    for (int i = 0; i < itemCount; i++) {
                        if (selection == i) {
                            int left = (width - circleRectItemWidth) / 2;
                            //选中的绘制圆角矩形
                            int top = selection * (circleRectRadius * 2 + spacing);
                            mRectF.set(left, top, left + circleRectItemWidth, top + circleRectItemHeight);
                            canvas.drawRoundRect(mRectF, circleRectCorner, circleRectCorner, selectedPaint);
                        } else {
                            //未选中的绘制圆点,距离需要判断position在选中的左边或者右边,从而确定cx
                            int cx1 = (width - 2 * circleRectRadius) / 2 + circleRectRadius;
                            float cy1 = 0;
                            if (selection < i) {
                                cy1 = (i - 1) * circleRectRadius * 2 + i * spacing + circleRectItemHeight + circleRectRadius;
                            } else {
                                cy1 = i * (circleRectRadius * 2) + i * spacing + circleRectRadius;
                            }
                            canvas.drawCircle(cx1, cy1, circleRectRadius, normalPaint);
                        }

                    }
                    break;
            }
        }
    }

    /**
     * 关联ViewPager
     *
     * @param viewPager
     */
    public void attachToViewPager(ViewPager viewPager) {
        this.viewPager = viewPager;
        PagerAdapter pagerAdapter = viewPager.getAdapter();
        if (pagerAdapter != null) {
            //TODO 如果项目使用了阿里开源库,UltraViewPager,想要兼容需要用以下方式获取 itemCount,否则去除这个if条件
            if (pagerAdapter instanceof UltraViewPagerAdapter) {
                //从UltraViewPagerAdapter获取真实的个数
                itemCount = ((UltraViewPagerAdapter) pagerAdapter).getRealCount();
            } else {
                itemCount = pagerAdapter.getCount();
            }
            selection = viewPager.getCurrentItem() % itemCount;
            checkItemCount();
        }

        viewPager.addOnPageChangeListener(this);
    }

    /**
     * 设置选中的值,当ViewPager只有一个item不显示指示器
     */
    private void checkItemCount() {
        if (selection >= itemCount) {
            selection = itemCount - 1;
        }
        setVisibility((itemCount <= 1) ? GONE : VISIBLE);
    }

    @Override
    public void onPageSelected(int i) {
        if (viewPager != null) {
            PagerAdapter pagerAdapter = viewPager.getAdapter();
            if (pagerAdapter != null) {
                selection = viewPager.getCurrentItem() % itemCount;
            }
        }
        postInvalidate();
    }

    @Override
    public void onPageScrolled(int i, float v, int i1) {

    }


    @Override
    public void onPageScrollStateChanged(int i) {

    }

    /**
     * dp to px
     */
    public int dip2px(float dpValue) {
        final float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}

4.attrs文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="Indicator">
        <!--未选中的指示器颜色-->
        <attr name="normal_color" format="reference|color" />
        <!--选中的指示器颜色-->
        <attr name="selected_color" format="reference|color" />
        <!--指示器每个item之间的间距-->
        <attr name="spacing" format="dimension" />
        <!--指示器排列方向-->
        <attr name="orientation" format="enum">
            <enum name="horizontal" value="0" />
            <enum name="vertical" value="1" />
        </attr>

        <!--指示器类型 命名规则:未选中样式_选中样式-->
        <attr name="style" format="enum">
            <!--都是圆点-->
            <enum name="circle_circle" value="0"/>
            <!--都是方形-->
            <enum name="rect_rect" value="1" />
            <!--未选中是圆点,选中是方形-->
            <enum name="circle_rect" value="2" />
        </attr>

        <!--都是圆点指示器半径大小-->
        <attr name="circle_circle_radius" format="dimension" />

        <!--都是方形指示器长度-->
        <attr name="rect_rect_itemWidth" format="dimension" />
        <!--都是方形指示器高度-->
        <attr name="rect_rect_itemHeight" format="dimension" />
        <!--都是方形指示器圆角-->
        <attr name="rect_rect_corner" format="dimension" />

        <!--circle_rect 模式圆点半径-->
        <attr name="circle_rect_radius" format="dimension" />
        <!--circle_rect 模式方形宽度-->
        <attr name="circle_rect_itemWidth" format="dimension" />
        <!--circle_rect 模式方形高度-->
        <attr name="circle_rect_itemHeight" format="dimension" />
        <!--circle_rect 模式方形圆角-->
        <attr name="circle_rect_corner" format="dimension" />

    </declare-styleable>
</resources>

 作者地址:https://www.jianshu.com/p/42811a7c708c

5.相关轮播图功能源码:

https://github.com/XW837156540/Banner

https://github.com/bingoogolapple/BGABanner-Android

https://github.com/wenzhihao123/Android-Universal-ViewPager-Indicator

https://github.com/Allure0/LMBanners

https://github.com/qdxxxx/BezierViewPager

https://github.com/GitHubZJY/ZJYWidget

https://github.com/dengzhi00/BzCircle

https://github.com/wuxianghua/CustomBanner

https://www.dandroid.cn/?p=2221

https://www.dandroid.cn/?p=3946

https://github.com/tokiii/RevealBanner    仿转转banner动画

https://blog.csdn.net/u014133119/article/details/80954317

6.小记:

https://github.com/bingoogolapple/BGABanner-Android中,设置banner图片以圆角显示,设置圆角简单,可以使用自定义ImageView,但是在滑动过程中会出现直角的情况,这时,只需要对父View进行裁剪即可:

java写法:


main_banner.setOutlineProvider(new ViewOutlineProvider() {
            @Override
            public void getOutline(View view, Outline outline) {
                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), 30);
            }
        });
 
main_banner.setClipToOutline(true);

kotlin写法:

//设置轮播图圆角的方法
            binding!!.banner.setOutlineProvider(object : ViewOutlineProvider() {
                override fun getOutline(view: View, outline: Outline) {
                    outline.setRoundRect(0, 0, view.width, view.height, 30f)
                }
            })
            binding!!.banner.clipToOutline = true

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中,可以使用第三方库来实现轮播图效果,其中一个常用的库是Banner。在使用Banner库时,可以通过设置一些属性来自定义轮播图的效果。例如,可以设置轮播间隔时间、轮播图的圆角等属性。\[1\] 此外,还可以设置轮播图的样式,内置样式有多种可供选择,可以根据需求进行设置。可以设置图片的加载方式,设置图片的网址或地址集合,设置轮播图的标题集合等。还可以设置是否自动轮播、显示器的位置等。\[2\] 如果想要实现一个简单的轮播图效果,可以使用Banner框架提供的BannerImageAdapter适配器。可以通过设置适配器来加载轮播图的数据,并在适配器中设置图片的显示方式。\[3\] 总结起来,使用Banner库可以方便地实现Android中的轮播图效果,通过设置属性和适配器来自定义轮播图的样式和数据。 #### 引用[.reference_title] - *1* *3* [Android---Banner轮播图](https://blog.csdn.net/qq_44950283/article/details/128390186)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Android入门Banner轮播图的使用(详解)](https://blog.csdn.net/m0_53223811/article/details/122562021)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值