画一个实心圆
效果图
创建attrs.xml文件
在value文件夹下创建一个名为attrs.xml文件,为圆设置一个背景颜色的属性,代码如下:
<declare-styleable name="CircleView_Solid"> <attr name="CircleColor_Solid" format="color"/> </declare-styleable>
初始化样式属性
为圆设置颜色属性,并设置抗锯齿
private void InitAttrs(Context context , AttributeSet attrs){ TypedArray array = context.getTheme().obtainStyledAttributes( attrs,R.styleable.CircleView_Solid,0,0 ); mCircleBGColor = array.getColor( R.styleable.CircleView_Solid_CircleColor_Solid,0xFFFFFFFF ); } private void InitVar(){ mCirclePaint = new Paint( ); mCirclePaint.setAntiAlias( true ); mCirclePaint.setColor( mCircleBGColor ); }
支持Padding属性
由于直接继承view,不再onDraw()中进行处理,是无法直接使用Padding属性,代码如下:
protected void onDraw(Canvas canvas) { super.onDraw( canvas ); int PaddingLeft = getPaddingLeft(); int PaddingRight = getPaddingRight(); int PaddingTop = getPaddingTop(); int PaddingBottom = getPaddingBottom(); int Width = (getWidth() - (PaddingLeft+PaddingRight)) / 2 +PaddingLeft; int Height = (getHeight() -(PaddingTop+PaddingBottom))/2+PaddingTop; int Radius = Math.min( Width,Height )/2; canvas.drawCircle( Width,Height,Radius,mCirclePaint ); }
支持wrap_content属性
若不在onMeasure()对wrap_content进行处理,效果很可能达不到预期效果,如果控件使用wrap_content属性,那么他的Measure specification mode就为At_Most,而它的宽高就等于specSize,这种情况下specSize是就相当于父容器当前剩余的大小,代码如下:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure( widthMeasureSpec, heightMeasureSpec ); int Width = 500; int Height = 500; int WidthMode = MeasureSpec.getMode( widthMeasureSpec ); int WidthSize = MeasureSpec.getSize( widthMeasureSpec ); int HeightMode = MeasureSpec.getMode( heightMeasureSpec ); int HeightSize = MeasureSpec.getSize( heightMeasureSpec ); if (WidthMode == MeasureSpec.AT_MOST && HeightMode == MeasureSpec.AT_MOST){ setMeasuredDimension( Math.min( Width,HeightSize ),Math.min( Height ,HeightSize) ); } else if (WidthMode == MeasureSpec.AT_MOST) { setMeasuredDimension( Math.min( Width,HeightSize ),HeightSize ); }else if (HeightMode == MeasureSpec.AT_MOST){ setMeasuredDimension( WidthSize,Math.min( Height ,HeightSize) ); } }
布局文件中的应用
<com.franzliszt.customcircleview.CircleView_Solid android:layout_width="wrap_content" android:layout_height="wrap_content" app:CircleColor_Solid="@color/colorRed" android:padding="10dp"/>
画一个带外圆环的圆
效果图
创建attrs.xml文件
<declare-styleable name="CircleView_Text"> <!-- 内圆颜色--> <attr name="CircleColor" format="color"/> <!-- 外圆环颜色--> <attr name="RingColor" format="color"/> <!-- 圆的半径--> <attr name="Radius" format="dimension"/> <!-- 外圆环的宽度--> <attr name="StrokeWidth" format="dimension"/> </declare-styleable>
初始化样式属性
private void InitAttrs(Context context , AttributeSet attrs){ TypedArray array = context.getTheme().obtainStyledAttributes( attrs,R.styleable.CircleView_Text,0,0 ); CircleColor = array.getColor( R.styleable.CircleView_Text_CircleColor,0xFFFFFFFF ); RingColor = array.getColor( R.styleable.CircleView_Text_RingColor,0xFFFFFFFF ); mRadius = array.getDimension( R.styleable.CircleView_Text_Radius,80 ); mStrokeWidth = array.getDimension( R.styleable.CircleView_Text_StrokeWidth,10 ); mRingRadius = mRadius + mStrokeWidth / 2; } private void InitVar(){ //内圆 //设置颜色 CirclePaint.setColor( CircleColor ); //设置填充方式 CirclePaint.setStyle( Paint.Style.FILL ); //设置抗锯齿 CirclePaint.setAntiAlias( true ); //外圆环 RingPaint.setColor( RingColor ); RingPaint.setStyle( Paint.Style.STROKE ); RingPaint.setAntiAlias( true ); RingPaint.setStrokeWidth( mStrokeWidth ); }
内圆与外圆环的绘制
protected void onDraw(Canvas canvas) { super.onDraw( canvas ); mCenterX = getWidth()/2; mCenterY = getHeight()/2; canvas.drawCircle( mCenterX,mCenterY,mRadius,CirclePaint ); RectF rect = new RectF( ); rect.left = mCenterX - mRingRadius; rect.right = 2 * mRingRadius + (mCenterX - mRingRadius); rect.top = mCenterY - mRingRadius; rect.bottom = 2 * mRingRadius + (mCenterY - mRingRadius); canvas.drawArc( rect,0,360,false,RingPaint ); }
布局文件中的应用
<com.franzliszt.customcircleview.CircleView android:layout_width="100dp" android:layout_height="100dp" app:Radius="40dp" app:StrokeWidth="10dp" app:CircleColor="@color/colorBlack" app:RingColor="@color/colorRed"/>
画一个外圆环可根据数值变动的圆
效果图
创建attrs.xml文件
<declare-styleable name="CircleView_Progress"> <!-- 内圆颜色--> <attr name="CircleProgressColor" format="color"/> <!-- 外圆环颜色--> <attr name="RingProgressColor" format="color"/> <!-- 外圆环覆盖部分颜色--> <attr name="RingBgProgressColor" format="color"/> <!-- 文字颜色--> <attr name="TextProgressColor" format="color"/> <!-- 圆的半径--> <attr name="RadiusProgress" format="dimension"/> <!-- 外圆环的宽度--> <attr name="StrokeWidthProgress" format="dimension"/> <attr name="CurrentProgress" format="float"/> </declare-styleable>
初始化样式属性
private void InitAttrs(Context context , AttributeSet attrs){ TypedArray array = context.getTheme().obtainStyledAttributes( attrs,R.styleable.CircleView_Progress,0,0 ); CircleColor = array.getColor( R.styleable.CircleView_Progress_CircleProgressColor,0xFFFFFFFF ); RingColor = array.getColor( R.styleable.CircleView_Progress_RingProgressColor,0xFFFFFFFF ); RingBgColor = array.getColor( R.styleable.CircleView_Progress_RingBgProgressColor,0xFFFFFFFF ); TextColor = array.getColor( R.styleable.CircleView_Progress_TextProgressColor, 0xFFFFFFFF); mRadius = array.getDimension( R.styleable.CircleView_Progress_RadiusProgress,80 ); mStrokeWidth = array.getDimension( R.styleable.CircleView_Progress_StrokeWidthProgress,10 ); mCurrentProgress = array.getFloat( R.styleable.CircleView_Progress_CurrentProgress,10 ); mRingRadius = mRadius + mStrokeWidth / 2; } private void InitVar(){ //内圆 //设置颜色 CirclePaint.setColor( CircleColor ); //设置填充方式 CirclePaint.setStyle( Paint.Style.FILL ); //设置抗锯齿 CirclePaint.setAntiAlias( true ); //外圆环 RingPaint.setColor( RingColor ); RingPaint.setStyle( Paint.Style.STROKE ); RingPaint.setAntiAlias( true ); RingPaint.setStrokeWidth( mStrokeWidth ); //外圆环覆盖部分 RingBgPaint.setColor( RingBgColor ); RingBgPaint.setStyle( Paint.Style.STROKE ); RingBgPaint.setAntiAlias( true ); RingBgPaint.setStrokeWidth( mStrokeWidth ); //中间文字 TextPaint.setStyle( Paint.Style.FILL ); TextPaint.setAntiAlias( true ); TextPaint.setColor( TextColor ); TextPaint.setTextSize( mRadius/2 ); //文字的高度 Paint.FontMetrics fontMetrics = TextPaint.getFontMetrics(); mTextHeight = (int)Math.ceil( fontMetrics.descent - fontMetrics.ascent ); }
绘制View
protected void onDraw(Canvas canvas) { super.onDraw( canvas ); mCenterX = getWidth()/2; mCenterY = getHeight()/2; canvas.drawCircle( mCenterX,mCenterY,mRadius,CirclePaint ); RectF rect = new RectF( ); rect.left = mCenterX - mRingRadius; rect.right = 2 * mRingRadius + (mCenterX - mRingRadius); rect.top = mCenterY - mRingRadius; rect.bottom = 2 * mRingRadius + (mCenterY - mRingRadius); canvas.drawArc( rect,0,360,false,RingPaint ); //当mCurrentProgress大于0时,外圆环覆盖部分显示 if (mCurrentProgress > 0){ RectF rect_progress = new RectF( ); rect_progress.left = mCenterX - mRingRadius; rect_progress.right = 2 * mRingRadius + (mCenterX - mRingRadius); rect_progress.top = mCenterY - mRingRadius; rect_progress.bottom = 2 * mRingRadius + (mCenterY - mRingRadius); //例如外圆环数值为35,即35/100*360,获得外圆环覆盖部分 canvas.drawArc( rect,-90,(float) (mCurrentProgress / mTotalProgress)*360,false,RingBgPaint ); } //文字部分 String text = mCurrentProgress+"%"; //文字部分的宽度 mTextWidth = TextPaint.measureText( text,0,text.length() ); canvas.drawText( text,mCenterX - mTextWidth / 2, mCenterY + mTextHeight / 4,TextPaint ); }
提供方法修改样式
public void setProgress(double progress){ mCurrentProgress = progress; postInvalidate(); } public void setRingBgColor(int Color){ RingBgColor = Color; postInvalidate(); } public void setTextColor(int Color){ TextColor = Color; postInvalidate(); }
布局文件中的应用
<com.franzliszt.customcircleview.CircleView_ProgressBar android:id="@+id/Progress" android:layout_width="200dp" android:layout_height="200dp" android:layout_marginTop="50dp" app:Radius="100dp" app:StrokeWidth="10dp" app:CircleColor="@color/colorWhite" app:RingColor="@color/colorGrey" app:RingProgressColor="@color/colorRed" app:TextProgressColor="@color/colorPrimary" app:CurrentProgress="59" />