一.源码:
支持无限循环轮播
支持圆形指示器
支持方形指示器
支持圆角方形指示器
支持修改轮播时间
支持自定义显示内容
支持指示器颜色大小修改
支持图片监听跳转
支持触摸停止轮播动画
二.效果图:
记得添加依赖(阿里开源库):
//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>
共用属性
属性 | 说明 |
| 未选中的指示器颜色 |
| 选中的指示器颜色 |
| 指示器每个item之间的间距 |
| 设置指示器排列方向,枚举类型,有 |
| 枚举类型,有如下几种类型 |
style样式说明
style | 说明 |
| 圆点指示器,对应图中第三个指示器样式 |
| 长条指示器,对应图中第二个指示器样式 |
| 指示器选中是长条,未选中是圆点,对应图中第一个指示器样式 |
如果style
设置为 circle_circle
可设置以下属性:
属性 | 说明 |
| 都是圆点指示器半径大小 |
如果style
设置为 rect_rect
可设置以下属性:
属性 | 说明 |
| 条形长度 |
| 条形高度 |
| 条形圆角 |
如果style
设置为 circle_rect
可设置以下属性:
属性 | 说明 |
| 未选中圆点半径 |
| 选中条形长度 |
| 选中条形高度 |
| 选中条形设置圆角 |
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>
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