先上效果图
知识点
1. Canvas简单操作
2. 阴影效果的实现
3. 动画效果的实现
个人觉得,像这样比较简单的控件,并且使用场合不多的情况下,无须按照标准的自定义View的步骤来, 我指的是在attr.xml中定义并声明属性,然后再从控件中获取TypedArray。不光写起来麻烦,而且引用也麻烦
将下面代码直接Copy到项目中,AS会将包名也改掉,一步到位。再根据自己的需求,简单修改即可。
package com.minicup.custom.progressbar;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
/**
* Created by gy on 2017/12/27.
*/
public class CircleView extends View {
/**
* 中间圆及进度条颜色
*/
private String mReachColor = "#54c484";
/**
* 默认外环背景颜色
*/
private String mDefaultColor = "#dddddd";
private Paint mCenterPaint;
private Paint mRingPaint;
private Paint mTextPaint;
/**
* ACTION_UP时的阴影
*/
private BlurMaskFilter maskfilterUp;
/**
* ACTION_DOWN时的阴影
*/
private BlurMaskFilter maskfilterDown;
private RectF ringRect;
/**
* 外环宽度
*/
private int mRingWidth = dp2px(10);
/**
* 阴影大小
*/
private int mShadowRadius = dp2px(5);
/**
* 控件的大小
*/
private int mViewRadius = dp2px(100);
/**
* 起使角度
*/
private float startAngle = 0;
/**
* 终止角度
*/
private float endAngle = 0;
/**
* 动画时,当前的角度
*/
private float currentAngle;
/**
* 中央文字
*/
private String mPercentage = "";
/**
* 字体大小
*/
private int mTextSize = 30;
private ValueAnimator anim;
/**
* 动画时,当前的百分比
*/
private int p;
public CircleView(Context context) {
super(context, null);
}
public CircleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
setLayerType(LAYER_TYPE_SOFTWARE, null);
mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
maskfilterUp = new BlurMaskFilter(mShadowRadius, BlurMaskFilter.Blur.SOLID);
maskfilterDown = new BlurMaskFilter(mShadowRadius*2, BlurMaskFilter.Blur.SOLID);
mCenterPaint.setMaskFilter(maskfilterUp);
mCenterPaint.setColor(Color.parseColor(mReachColor));
mRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mRingPaint.setColor(Color.parseColor(mDefaultColor));
mRingPaint.setStrokeCap(Paint.Cap.ROUND);
mRingPaint.setStrokeWidth(mRingWidth);
mRingPaint.setStyle(Paint.Style.STROKE);
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(Color.WHITE);
mTextPaint.setTextSize(spTopx(mTextSize));
mTextPaint.setTypeface(Typeface.SANS_SERIF);
//这里应该在Activity中设置
setPercentage(70);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
ringRect = new RectF(mRingWidth/2, mRingWidth/2, w-mRingWidth/2, w-mRingWidth/2);
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(mViewRadius*2, mViewRadius*2);
}
@Override
protected void onDraw(Canvas canvas) {
int radius = mViewRadius;
//中央圆
canvas.drawCircle(radius, radius, radius * 0.8f, mCenterPaint);
//外环背景
mRingPaint.setColor(Color.parseColor(mDefaultColor));
canvas.drawCircle(radius, radius, radius-mRingWidth/2, mRingPaint);
//外环进度
mRingPaint.setColor(Color.parseColor(mReachColor));
canvas.drawArc(ringRect, startAngle, currentAngle, false, mRingPaint);
//中央文字
Rect rect = new Rect();
mTextPaint.getTextBounds(mPercentage, 0, mPercentage.length(), rect);
canvas.drawText(mPercentage, 0, mPercentage.length(), radius-rect.width()/2, radius+rect.height()/2, mTextPaint);
super.onDraw(canvas);
}
public int dp2px(int dp){
return ((int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()) + 0.5));
}
private float spTopx(int sp) {
return ((int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics()) + 0.5));
}
/**
* 用以实现点击效果
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
int actionMasked = event.getActionMasked();
if(actionMasked==MotionEvent.ACTION_DOWN){
mCenterPaint.setMaskFilter(maskfilterDown);
startAnimation();
postInvalidate();
}else if(actionMasked==MotionEvent.ACTION_UP){
mCenterPaint.setMaskFilter(maskfilterUp);
postInvalidate();
}
return true;
}
public void setPercentage(int p) {
endAngle = 360 * p / 100;
this.p = p;
mPercentage = String.format("%s%%", p);
startAnimation();
}
public void startAnimation(){
anim = ValueAnimator.ofFloat(startAngle, endAngle);
anim.setInterpolator(new DecelerateInterpolator(1.1f));
anim.setDuration(1000);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentAngle = (Float) animation.getAnimatedValue();
mPercentage = String.format("%s%%", ((int) (p * currentAngle / endAngle)));
postInvalidate();
}
});
anim.start();
}
}