感谢AigeStudio提供的自定义view讲解(地址http://blog.csdn.net/aigestudio)下面是我看了Aige的讲解之后自己的理解以及demo,有说错的地方欢迎大家指出。
在这里自定义一个圆形等级条的view来加强自己对自定义的理解。
思路:
1、需要画一个背景圆,再需要一个覆盖在背景圆上面的进度圆。
2、使用线程让进度圆产生动画。
3、在进度圆达到圆满的时候回到原点,给个回调。
现在我们先画出一个空心圆。
代码块
/** 背景圆的画笔 */
private Paint paint;
/** 进度条圆的画笔 */
private Paint paint1;
/** 设置矩阵的坐标点 */
private RectF rectF;
/** 屏幕的高度 */
private int width = 0;
/** 园的半径 */
private int circleRadius = 0;
/** 园的y轴起始坐标 */
private int circleStartY = 20;
/** 园的y轴终点坐标 起始坐标加上园的半径*2 */
private int circleEndy = 0;
/**我一般喜欢直接写3个构造方法,方便引用*/
public CircleView(Context context) {
super(context);
init(context);
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
/**初始化画笔*/
private void init(Context context){
paint = new Paint();// 布局xml里面引用
paint1 = new Paint();// 布局xml里面引用
paint.setAntiAlias(true);// 设置抗锯齿
paint.setColor(getResources().getColor(R.color.char_circlebackground));
paint.setStyle(Style.STROKE);// 设置圆心掏空
paint.setStrokeWidth(dip2px(context, 10));
// 设置画笔形状 圆形,需要先设置画笔样式 SYROKE 或者 FILL_AND_STROKE
paint.setStrokeCap(Paint.Cap.ROUND);
paint1.setAntiAlias(true);// 设置抗锯齿
paint1.setColor(getResources().getColor(R.color.char_circleplan));
paint1.setStyle(Style.STROKE);
paint1.setStrokeWidth(dip2px(context, 10));
paint1.setStrokeCap(Paint.Cap.ROUND);
width = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
circleRadius = width / 4;
circleEndy = circleStartY + circleRadius * 2;
rectF = new RectF(width / 2 - circleRadius, circleStartY, width / 2 + circleRadius, circleEndy);// 弧形
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 第一个参数是圆的大小,根据矩阵来控制。第二个参数是在哪个点起始,已顺时针方向走,所以说90为正下方。0为最右边。第三个参数是圆的度数360为一圈
canvas.drawArc(rectF, 90, 360, false, paint);
//这里等级为4/1等级,所以是90
canvas.drawArc(rectF, 90, 90, false, paint1);
}
/**传入dp,返回px*/
public float dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (float) (dpValue * scale + 0.5f);
}
效果如下:
效果已经画出来了。但是缺少点东西,现在view里面东西全是死的,得让他活起来,并且具有动画,满级之后自动反0操作。所以我加了以下代码
/** 背景圆的画笔 */
private Paint paint;
/** 进度条圆的画笔 */
private Paint paint1;
/** 设置矩阵的坐标点 */
private RectF rectF;
/** 屏幕的高度 */
private int width = 0;
/** 园的半径 */
private int circleRadius = 0;
/** 园的y轴起始坐标 */
private int circleStartY = 20;
/** 园的y轴终点坐标 起始坐标加上园的半径*2 */
private int circleEndy = 0;
/** 初始进度 */
private float currentPorcent = 0;
/** 进度是多少 */
private float maxPorcent = 0;
/**满级回调*/
public RestoreCirclr rc;
/** 是否还原 */
public boolean isRestore = false;
/**我一般喜欢直接写3个构造方法,方便引用*/
public CircleView(Context context) {
super(context);
init(context);
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
/**初始化画笔*/
private void init(Context context){
paint = new Paint();// 布局xml里面引用
paint1 = new Paint();// 布局xml里面引用
paint.setAntiAlias(true);// 设置抗锯齿
paint.setColor(getResources().getColor(R.color.char_circlebackground));
paint.setStyle(Style.STROKE);// 设置圆心掏空
paint.setStrokeWidth(dip2px(context, 10));
// 设置画笔形状 圆形,需要先设置画笔样式 SYROKE 或者 FILL_AND_STROKE
paint.setStrokeCap(Paint.Cap.ROUND);
paint1.setAntiAlias(true);// 设置抗锯齿
paint1.setColor(getResources().getColor(R.color.char_circleplan));
paint1.setStyle(Style.STROKE);
paint1.setStrokeWidth(dip2px(context, 10));
paint1.setStrokeCap(Paint.Cap.ROUND);
width = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
circleRadius = width / 4;
circleEndy = circleStartY + circleRadius * 2;
rectF = new RectF(width / 2 - circleRadius, circleStartY, width / 2 + circleRadius, circleEndy);// 弧形
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 第一个参数是圆的大小,根据矩阵来控制。第二个参数是在哪个点起始,已顺时针方向走,所以说90为正下方。0为最右边。第三个参数是圆的度数360为一圈
canvas.drawArc(rectF, 90, 360, false, paint);
//这里等级为4/1等级,所以是90
canvas.drawArc(rectF, 90, currentPorcent, false, paint1);
if (currentPorcent == 0) {
handler.postDelayed(drawRunnable, 0);
}
}
/**启动动画刷新界面*/
public void invalidateView(){
handler.postDelayed(drawRunnable, 0);
}
private Handler handler = new Handler();
Runnable drawRunnable = new Runnable() {
@Override
public void run() {
if (!isRestore) {//有经验时动画
if (currentPorcent >= maxPorcent) {
currentPorcent = maxPorcent;
invalidate();
//移除当前Runnable
handler.removeCallbacks(drawRunnable);
} else {
currentPorcent += 5;//这里是动画速度,当前为5。可自己去调试经验值增长速度
handler.postDelayed(drawRunnable, (long) (1300 / maxPorcent));
invalidate();
}
if (currentPorcent == 360) {
if (rc != null) {
isRestore = rc.OnRestoreCirclr();
handler.postDelayed(drawRunnable, 0);
}
}
} else {//满级之后经验条动画返回0进度
if (currentPorcent <= 0) {
currentPorcent = 0;
invalidate();
handler.removeCallbacks(drawRunnable);
} else {
currentPorcent -= 3;//这里是动画速度,当前为3。可自己去调试经验值反0速度
handler.postDelayed(drawRunnable, (long) (1300 / maxPorcent));
invalidate();
}
}
}
};
public boolean isRestore() {
return isRestore;
}
public void setRestore(boolean isRestore) {
this.isRestore = isRestore;
}
/** 设置等级进度,传入升级经验,以及当前经验 maxPorcent就是当前经验在升级经验占的百分比*/
public void setCirclePlan(int max, int current) {
maxPorcent = (int) (((float)360 / (float)max) * current);
}
/**传入dp,返回px*/
public float dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (float) (dpValue * scale + 0.5f);
}
/** 设置园线的颜色 */
public void setCircleColor(int color) {
paint.setColor(color);
}
/** 设置进度线的颜色 */
public void setCirclePlanColor(int color) {
paint1.setColor(color);
}
public void setRc(RestoreCirclr rc) {
this.rc = rc;
}
public interface RestoreCirclr {
public boolean OnRestoreCirclr();
}
在mainActivity里面调用代码如下:
private CircleView circleView;
/** 升级经验为100 */
private int max ;
/** 目前经验值为10 */
private int current ;
/** 经验加10 */
private Button button_1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
circleView = (CircleView) findViewById(R.id.circleView);
button_1 = (Button) findViewById(R.id.button_1);
button_1.setOnClickListener(this);
max = 100;
current = 10;
circleView.setCirclePlan(max, current);// 进度条已满 升级数是100,当前经验数是10
circleView.setRc(new RestoreCirclr() {// 满级之后的回调
@Override
public boolean OnRestoreCirclr() {
//满级之后的操作 返回true就回到原点
current=0;
return true;
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_1:
current += 10;
circleView.setRestore(false); //false经验值增加
circleView.setCirclePlan(max, current);
circleView.invalidateView();//刷新view
break;
}
}
效果图:
由于本人第一次写博客,不会制作那种可动的gif图片,所以导致动画效果看不见。如果各位有兴趣的看看动画效果可去(http://download.csdn.net/detail/u013895206/8431395)这个地址下载源码。
本篇自定义view学习就到这里,欢迎大家指正错误。互相学习。第一次专注的写博客,希望各位大大多多支持。提前祝福兄弟姐妹们新年快乐。。
未完待续、、、