转载请标明出处: http://blog.csdn.net/airsaid/article/details/52904344
本文出自:周游的博客
最近公司项目中,有一个如下的UI:
可以看到,右侧的圆点,虽然可以直接用布局实现,但是由于很多地方都出现了,所以考虑到复用性不高。可以直接用自定义View来实现,扩展性和复用性都很好,并且这个View也很简单,直接画圆就行了。
首先来定义需要用到的自定义属性:
<declare-styleable name="IndicateDotView">
<attr name="indicate_select_color" format="color"/>
<attr name="indicate_unselect_color" format="color"/>
<attr name="indicate_margin" format="dimension"/>
<attr name="indicate_radius" format="dimension"/>
<attr name="indicate_number" format="integer"/>
<attr name="indicate_max_number" format="integer"/>
<attr name="indicate_is_least_one" format="boolean"/>
<attr name="indicate_divide_color" format="color"/>
<attr name="indicate_divide_width" format="dimension"/>
<attr name="android:clickable" />
declare-styleable>
在代码中获取:
public IndicateDotView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.IndicateDotView);
mUnSelectColor = a.getColor(R.styleable.IndicateDotView_indicate_unselect_color, mUnSelectColor);
mSelectColor = a.getColor(R.styleable.IndicateDotView_indicate_select_color, mSelectColor);
mDivideWidth = (int) a.getDimension(R.styleable.IndicateDotView_indicate_divide_width, mDivideWidth);
mDivideColor = a.getColor(R.styleable.IndicateDotView_indicate_divide_color, mDivideColor);
mIsLeastOne = a.getBoolean(R.styleable.IndicateDotView_indicate_is_least_one, mIsLeastOne);
mMargin = (int) a.getDimension(R.styleable.IndicateDotView_indicate_margin, mMargin);
mRadius = (int) a.getDimension(R.styleable.IndicateDotView_indicate_radius, mRadius);
mClickable = a.getBoolean(R.styleable.IndicateDotView_android_clickable, mClickable);
mMaxNumber = a.getInt(R.styleable.IndicateDotView_indicate_max_number, mMaxNumber);
mNumber = a.getInt(R.styleable.IndicateDotView_indicate_number, mNumber);
a.recycle();
mPaint = new Paint();
mPaint.setAntiAlias(true);
}
onDraw()中绘制:
@Override
protected void onDraw(Canvas canvas) {
if(mNumber > mMaxNumber){
if(mIsLeastOne){
mNumber = 1;
}else{
mNumber = 0;
}
}
for (int i = 0; i < mMaxNumber; i++) {
if(i < mNumber){
mPaint.setColor(mSelectColor);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
drawCircle(canvas, i);
}else{
mPaint.setColor(mUnSelectColor);
mPaint.setStyle(Paint.Style.FILL);
drawCircle(canvas, i);
if(mDivideColor != -1){
mPaint.setColor(mDivideColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mDivideWidth);
drawCircle(canvas, i);
}
}
}
}
代码很简单,就是根据最大圆点数循环绘制圆以及边框,绘制圆的代码如下:
private void drawCircle(Canvas canvas, int i){
canvas.drawCircle(getPaddingLeft() + mRadius + mDivideWidth + (((mRadius * 2)
+ (mDivideWidth * 2) + mMargin) * i), getHeight() / 2, mRadius, mPaint);
}
最后在onMeasure()计算宽高:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width = 0;
int height = 0;
if(widthMode != MeasureSpec.EXACTLY){
width = mMaxNumber * (mRadius * 2 + mDivideWidth * 2 + mMargin) + getPaddingLeft() + getPaddingRight();
}
if(heightMode != MeasureSpec.EXACTLY){
height = mRadius * 2 + mDivideWidth * 2 + getPaddingTop() + getPaddingBottom();
}
setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : width,
heightMode == MeasureSpec.EXACTLY ? heightSize : height);
}
GitHub地址:https://github.com/Airsaid/IndicateDotView