原理:
通过继承Android的View类,重写onDraw方法。
实现:
这次就直接上代码了
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
public class CycleView extends View {
Paint mPaint;
int progress = 30;
int start_degree = -90;
public CycleView(Context context, AttributeSet attrs) {
super(context, attrs);
InitResources(context, attrs);
}
int background_int;
int progress_int;
float layout_width_float;
int textColor_int;
float textSize_float;
int max_int;
Drawable thumb_double;
int thumbSize_int;
private void InitResources(Context context, AttributeSet attrs) {
TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.windows);
background_int = mTypedArray.getColor(R.styleable.windows_background, 0xFF87cfe8);
progress_int = mTypedArray.getColor(R.styleable.windows_progressDrawable, 0xFFabd800);
layout_width_float = mTypedArray.getDimension(R.styleable.windows_layout_width, 7);
textColor_int = mTypedArray.getColor(R.styleable.windows_textColor, 0xFFada1de);
textSize_float = mTypedArray.getDimension(R.styleable.windows_textSize, 50);
max_int = mTypedArray.getInt(R.styleable.windows_max, 100);
progress = mTypedArray.getInt(R.styleable.windows_progress, 20);
thumb_double = mTypedArray.getDrawable(R.styleable.windows_thumb);
thumbSize_int = mTypedArray.getInt(R.styleable.windows_thumbSize, 30);
mTypedArray.recycle();
if (thumb_double == null) {
Bitmap bitmap = Bitmap.createBitmap(thumbSize_int, thumbSize_int, Bitmap.Config.ARGB_8888);
// 图片画片
Canvas cas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setStyle(Style.FILL);
paint.setColor(0xFF68ba32);
int center = thumbSize_int / 2;
int radius = center - 4;
cas.drawCircle(center, center, radius, paint);
thumb_double = new BitmapDrawable(getResources(), bitmap);
}
mPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawProgressView(canvas);
}
private void drawProgressView(Canvas canvas) {
InitOval(canvas);
drawBackground(canvas);
drawProgress(canvas);
drawProgressText(canvas);
}
RectF oval;
private void InitOval(Canvas canvas) {
int center = getWidth() / 2;
int radius = (int) (center - thumbSize_int / 2);
// 画布中央减去半径就是左上角
int left_top = center - radius;
// 画布中央加上半径就是右下角
int right_bottom = center + radius;
if (oval == null) {
oval = new RectF(left_top, left_top, right_bottom, right_bottom);
}
}
/**
* 绘制进度文字
*
* @param canvas
*/
private void drawProgressText(Canvas canvas) {
mPaint.setTextSize(textSize_float);
mPaint.setColor(textColor_int);
mPaint.setStrokeWidth(2);
mPaint.setStyle(Style.FILL);
String progresstext = progress + "%";
float text_left = (getWidth() - mPaint.measureText(progresstext)) / 2;
FontMetrics fontMetrics = mPaint.getFontMetrics();
// 绘制文字是底部对齐
float text_top = (float) ((getHeight() / 2 + Math.ceil(fontMetrics.descent - fontMetrics.ascent) / 2));
canvas.drawText(progresstext, text_left, text_top, mPaint);
}
private void drawProgress(Canvas canvas) {
// 设置进度
mPaint.setColor(progress_int);
mPaint.setStrokeWidth(layout_width_float);
float seek = 0;
if (max_int > 0) {
seek = (float) progress / max_int * 360;
}
canvas.drawArc(oval, start_degree, seek, false, mPaint);
canvas.save();
int center = getWidth() / 2;
int radius = (int) (center - thumbSize_int / 2);
double cycle_round = (seek + start_degree) * Math.PI / 180;
float x = (float) (Math.cos(cycle_round) * (radius) + center - thumbSize_int / 2);
float y = (float) (Math.sin(cycle_round) * (radius) + center - thumbSize_int / 2);
thumb_double.setBounds(0, 0, thumbSize_int, thumbSize_int);
canvas.translate(x, y);
thumb_double.draw(canvas);
canvas.restore();
}
private void drawBackground(Canvas canvas) {
mPaint.setStrokeWidth(layout_width_float);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
// 设置背景
mPaint.setColor(background_int);
canvas.drawArc(oval, start_degree, 360, false, mPaint);
}
/**
* 查看Seekbar源码
*
* @param progress
*/
public synchronized void setProgress(int progress) {
if (progress > max_int) {
progress = max_int;
}
this.progress = progress;
postInvalidate();
}
public int getProgress() {
return this.progress;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (thumb_double != null) {
thumb_double.setCallback(null);
thumb_double = null;
}
}
}
然后是XML,因为要用到自定义属性<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 参考Seekbar -->
<declare-styleable name="windows">
<!-- 背景颜色 -->
<attr name="background" format="color" />
<!-- 进度颜色 -->
<attr name="progressDrawable" format="color" />
<!-- 宽度 -->
<attr name="layout_width" format="dimension" />
<!-- 字体颜色 -->
<attr name="textColor" format="color" />
<!-- 字体大小 -->
<attr name="textSize" format="dimension" />
<!-- 最大进度 -->
<attr name="max" format="integer" />
<!-- 进度 -->
<attr name="progress" format="integer" />
<!-- 进度点 -->
<attr name="thumb" format="reference" />
<!-- 进度点宽高 -->
<attr name="thumbSize" format="integer" />
</declare-styleable>
</resources>
最后是在代码里的用法
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<com.windows.canvas.CycleView
android:layout_centerInParent="true"
xmlns:windows="http://schemas.android.com/apk/res/com.finals.canvas"
android:layout_width="150dp"
android:layout_height="150dp" />
</RelativeLayout>
然后是效果图