一.drawCircle
(1)Fill And Stroke
public class CanvasView extends View {
private Paint mPaint;
private Context mContext;
public CanvasView(Context context) {
super(context);
init(context);
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mPaint = new Paint();
mContext = context;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int roundWidth = dp2px(20);
float center = getWidth() / 2;
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeWidth(roundWidth);
//去掉锯齿
mPaint.setAntiAlias(true);
//所画圆的中心 X坐标
//所画圆的中心 Y坐标
//所画圆的半径
//画圆要用的画笔
//drawCircle(float cx, float cy, float radius, Paint paint)
canvas.drawCircle(center, center, center - roundWidth / 2, mPaint);
}
public int dp2px(int dp) {
return (int) (dp * mContext.getResources().getDisplayMetrics().density + 0.5f);
}
}
(2)Fill
<pre name="code" class="java">@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int roundWidth = dp2px(20);
float center = getWidth() / 2;
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(roundWidth);
//去掉锯齿
mPaint.setAntiAlias(true);
//所画圆的中心 X坐标
//所画圆的中心 Y坐标
//所画圆的半径
//画圆要用的画笔
//drawCircle(float cx, float cy, float radius, Paint paint)
canvas.drawCircle(center, center, center - roundWidth / 2, mPaint);
}
(3)Stroke
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int roundWidth = dp2px(20);
float center = getWidth() / 2;
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(roundWidth);
//去掉锯齿
mPaint.setAntiAlias(true);
//所画圆的中心 X坐标
//所画圆的中心 Y坐标
//所画圆的半径
//画圆要用的画笔
//drawCircle(float cx, float cy, float radius, Paint paint)
canvas.drawCircle(center, center, center - roundWidth / 2, mPaint);
}
(4)半径问题
之前一直觉得如果一个圆的半径是R,画笔的宽度是D,那么这个宽度是圆的半径内还是半径外?下面展示的结果是,半径内外各一半D/2,所以我们只要用宽度为D的画笔,画半径为R-D/2的圆,效果就是半径为R的圆
设置的画笔的宽度(setStrokeWidth,这个宽度是半径内一半,半径外一半)
二.drawLine 和 drawText
public class CanvasView extends View {
private Paint mPaint;
private Paint mtextPaint;
private Context mContext;
public CanvasView(Context context) {
super(context);
init(context);
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mPaint = new Paint();
mContext = context;
mtextPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int roundWidth = dp2px(20);
float center = getWidth() / 2;
float lineLength = dp2px(20);
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(0);
/**
* 设置字体参数
* */
mtextPaint.setColor(Color.RED);
mtextPaint.setStyle(Paint.Style.STROKE);
mtextPaint.setTextSize(dp2px(18));
mtextPaint.setTypeface(Typeface.DEFAULT_BOLD);
/*** 画线:在view的中心点画个坐标轴
* */
canvas.translate(getWidth() / 2, getHeight() / 2);
//这时候(0,0)就是center的坐标!!!!!!
//drawLine(float startX, float startY, float stopX, float stopY, Paint paint)
canvas.drawLine(0, 0, center + lineLength, 0, mPaint);
canvas.drawLine(0, 0, 0, center + lineLength, mPaint);
/**
* 画出两个字母X,y
* */
<span style="white-space:pre"> </span>String strX = "X";
float strXSize = mtextPaint.measureText(strX);
//这时候坐标轴中心在这个View的中点
canvas.drawText(strX, center - dp2px(20), -dp2px(10), mtextPaint);
String strY = "Y";
// float strXSize = mtextPaint.measureText(strX);
canvas.drawText(strY, -dp2px(10), center - dp2px(20), mtextPaint);
}
public int dp2px(int dp) {
return (int) (dp * mContext.getResources().getDisplayMetrics().density + 0.5f);
}
}
(2).drawText产生的文字的问题
public class CanvasView extends View {
private Paint mPaint;
private Context mContext;
public CanvasView(Context context) {
super(context);
init(context);
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mPaint = new Paint();
mContext = context;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int TextSize = dp2px(20);
float center = getWidth() / 2;
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setTypeface(Typeface.DEFAULT_BOLD);
mPaint.setTextSize(TextSize);
//去掉锯齿
mPaint.setAntiAlias(true);
String textOne = "one";
String textTwo = "two";
float textOneSize = mPaint.measureText(textOne);
canvas.translate(center, center);
canvas.drawText(textOne, TextSize / 2, TextSize / 2, mPaint);
canvas.rotate(90);
canvas.drawText(textTwo, TextSize / 2, TextSize / 2, mPaint);
}
public int dp2px(int dp) {
return (int) (dp * mContext.getResources().getDisplayMetrics().density + 0.5f);
}
}
三.drawArc
public class CanvasView extends View {
private Paint mPaint;
private Context mContext;
public CanvasView(Context context) {
super(context);
init(context);
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mPaint = new Paint();
mContext = context;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int radius = dp2px(150) / 2;
int roundWidth = dp2px(20);
int center = getWidth() / 2;
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(roundWidth);
//画个弧形
RectF oval = new RectF(center - radius
, center - radius
, center + radius
, center + radius);
/*** drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
* Draw the specified arc, which will be scaled to fit inside the specified oval.
* 圆弧是内嵌于这个矩形的
* */
//-180开始转 转60度 true(画成扇形) false只画弧
//-180开始转 转60度 true(画成扇形) false只画弧
canvas.drawArc(oval, -180, 60, true, mPaint);
}
public int dp2px(int dp) {
return (int) (dp * mContext.getResources().getDisplayMetrics().density + 0.5f);
}
}
我觉得最难理解就是这个矩形跟圆的关系,下面就是他们之间的关系!!!
四.CanvasRotate(Canva的旋转)
public class CanvasView extends View {
private Paint mPaint;
private Context mContext;
public CanvasView(Context context) {
super(context);
init(context);
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mPaint = new Paint();
mContext = context;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**
* 本身矩形框的宽高就是 150dp 150dp
* */
//这个就把坐标系的原点改变为当前view的中心点(默认为左上角的顶点)
//!!!!!!!!!!!!!!!!!!!!!
canvas.translate(getWidth() / 2, getHeight() / 2);
/**
* 画一个蓝色的矩形
* */
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Paint.Style.STROKE);
//先画蓝色矩形
canvas.drawRect(dp2px(0), dp2px(0), dp2px(70), dp2px(50), mPaint);
/**
* 画一个红色的矩形
* */
//旋转画布
canvas.rotate(90);
//再画红色矩形
mPaint.setColor(Color.RED);
canvas.drawRect(dp2px(0), dp2px(0), dp2px(70), dp2px(50), mPaint);
/**
*
* 可以看出画布的坐标被移动的90度,画布没有动!!!!!!!
* */
}
public int dp2px(int dp) {
return (int) (dp * mContext.getResources().getDisplayMetrics().density + 0.5f);
}
}
可以看出画布的坐标被移动的90度,画布没有动!!!!!!!
画布的坐标被转了90度,画布本身没有转
五.Canvas Save Rotate(Canva的旋转和Save)
canvasRotate canvas转动 然后只是坐标变了
如果调用restore次数多于save就会报错!!!!
public class CanvasView extends View {
private Paint mPaint;
private Context mContext;
private Paint mTextPaint;
/**
* 圆环中间百分号颜色
*/
private int percentColor;
/**
* 圆环中间百分号尺寸
*/
private int percentSize;
public CanvasView(Context context) {
super(context);
init(context);
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mPaint = new Paint();
mTextPaint = new Paint();
mContext = context;
// “%”符号颜色、尺寸
percentColor = Color.parseColor("#ff0000");
percentSize = (int) dp2px(20);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTextPaint.setStrokeWidth(0);
mTextPaint.setColor(percentColor);
mTextPaint.setTextSize(percentSize);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
// 矩形宽度
int lenght = dp2px(50);
/**
* 坐标系原点变成了View的原点,不再是默认的View左上角
*
* */
canvas.translate(getWidth() / 2, getHeight() / 2);
// 第一个黑色矩形
canvas.drawRect(-lenght, -lenght, lenght, lenght, mPaint);
// 保存x轴方向为3点钟方向的坐标
canvas.save();
/**
* 旋转坐标轴
* 坐标系顺时针转了45度
* */
canvas.rotate(45);
mPaint.setColor(Color.BLUE);
// 第二个蓝色矩形
canvas.drawRect(-lenght, -lenght, lenght, lenght, mPaint);
/**
* 恢复坐标轴(刚才偏移了45度),变成了x水平
* */
canvas.restore();
mPaint.setColor(Color.RED);
// 绘制坐标轴
canvas.drawLine(0, 0, 300, 0, mPaint);
canvas.drawText("x", dp2px(50), 0, mTextPaint);
canvas.drawLine(0, 0, 0, 300, mPaint);
canvas.drawText("y", 0, dp2px(50), mTextPaint);
}
public int dp2px(int dp) {
return (int) (dp * mContext.getResources().getDisplayMetrics().density + 0.5f);
}
}
六.drawOval (画一个渐变色的圆,oval其实是椭圆的意思)
public class ZhiMaView extends View {
private Context mContext;
private final int[] mColors = new int[]{0xffff0000, 0xffffff00, 0xff00ff00,
0xff00ffff, 0xff0000ff, 0xffff00ff};// 渐变色环颜色
private Paint mPaint;
public ZhiMaView(Context context) {
super(context);
init(context);
}
public ZhiMaView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ZhiMaView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
this.mContext = context;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int CENTER_X = getWidth() / 2;
/**
* public SweepGradient (float cx, float cy, int[] colors, float[] positions)
Added in API level 1
A subclass of Shader that draws a sweep gradient around a center point.
Parameters
cx The x-coordinate of the center
cy The y-coordinate of the center
colors The colors to be distributed between around the center.
There must be at least 2 colors in the array.
positions May be NULL. The relative position of each corresponding color in the colors array,
beginning with 0 and ending with 1.0. If the values are not monotonic,
the drawing may produce unexpected results.
If positions is NULL, then the colors are automatically spaced evenly.
*
* */
//不太理解这个//围绕着一个中心点用着色器画渐变色
//A subclass of Shader that draws a sweep gradient around a center point.
Shader s = new SweepGradient(0, 0, mColors, null);
mPaint.setShader(s);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(40);
float r = CENTER_X - mPaint.getStrokeWidth() / 2;
canvas.save();
canvas.translate(CENTER_X, CENTER_X);// 移动中心
//canvas.rotate(150);
canvas.drawOval(new RectF(-r, -r, r, r), mPaint);// 画出色环和中心园
canvas.restore();
}
}
七.DrawBitmap
public class BitmapView extends View {
private Bitmap bitmap;
private Paint bitmapPaint= new Paint();
public BitmapView(Context context) {
super(context);
init();
}
public BitmapView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public BitmapView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.home_my_try_click);
bitmapPaint.setAntiAlias(true);
bitmapPaint.setColor(Color.BLACK);
bitmapPaint.setStyle(Paint.Style.FILL);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap,0,0,bitmapPaint);
}
}
//布局文件activity_main.xml
<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.weixin.drawbitmap.view.BitmapView
android:layout_width="300dp"
android:layout_height="300dp"/>
</RelativeLayout>
这里设置是从0,0开始画
这个时候这个view是center in Parent ,也是从(0,0)这个时候这个0,0是相对他的容器
(1)setTranslate和preTranslate还有postTranslate 之间的区别
<1>setTranslate
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Matrix matrix=new Matrix();
/**
* matrix.setScale(interpolatedTime, interpolatedTime);
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
经常在中心缩放的应用中看到这段代码.
preTranslate是指在setScale前,平移,postTranslate是指在setScale后平移
注意他们参数是平移的距离,而不是平移目的地的坐标!!!!!
由于缩放是以(0,0)为中心的,所以为了把界面的中心与(0,0)对齐,就要preTranslate(-centerX, -centerY),
setScale完成后,调用postTranslate(centerX, centerY),再把图片移回来,这样看到的动画效果就是activity的界面图片从中心不停的缩放了
注:centerX和centerY是界面中心的坐标
因为矩阵变换设计到合并矩阵的情况,所以才分了pre和post函数,可以参照skia库中SkMatrix.cpp函数原型。pre表示回受到先前的变换的影响,而post不会。比如
(1)
matrxi.scale(0.5, 0.5);
matrix.preTranslate(100, 0);
(2)
matrix.scale(0.5, 0.5);
matrix.postTranslate(100, 0);
第一段代码缩放后会再平移100*0.5=50的距离,而第二段代码缩放后会平移坐标给定的100的距离。
*
* */
matrix.postScale(0.5f, 0.5f);
matrix.preTranslate(240,0); //实际移动的距离是120 = 240 * 0.5f;
canvas.drawBitmap(bitmap,matrix,bitmapPaint);
}
<2>preTranslate
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Matrix matrix=new Matrix();
matrix.postScale(0.5f, 0.5f);
matrix.postTranslate(120,0);
canvas.drawBitmap(bitmap,matrix,bitmapPaint);
}
<1>和<2>的效果都是一样的如下图
八.DrawClock()画一个钟(一个简单的实践)
public class ClockView extends View {
private Context mContext;
private Paint mPaint;
private Paint mTextPaint;
public ClockView(Context context) {
super(context);
init(context);
}
public ClockView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mContext = context;
mPaint = new Paint();
mTextPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**
* 先画一个大圆,默认坐标系原点是View的左上角
* */
int center = getWidth() / 2;
int roundWidth = dp2px(10);
int radius = getWidth() / 2 - dp2px(100) / 2 - roundWidth / 2;
int textWidth = dp2px(10);
//去掉锯齿
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(roundWidth);
canvas.drawCircle(center, center, radius, mPaint);
/**
*画刻度还有数字
* */
//刻度线不要那么宽
mPaint.setStrokeWidth(0);
//刻度线换一种颜色
// mPaint.setColor(Color.BLACK);
mTextPaint.setStrokeWidth(0);
mTextPaint.setColor(Color.RED);
mTextPaint.setTextSize(textWidth);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
canvas.translate(center, center);
//这时候坐标系 X轴在三点钟方向 Y轴在六点钟方向
canvas.save();
//坐标系原点从原来的View的左上角顶点移到View的中心
//从刻度1开始画(坐标轴逆时针转60)
canvas.rotate(-60);
for (int i = 0; i < 60; i++) {
if (i % 5 == 0) {
//每五个小格就是一个大格,所以画长刻度
canvas.drawLine(radius, 0, radius + dp2px(25), 0, mPaint);
//这时候坐标系 X轴在一点钟方向 Y轴在4点钟方向
//这个save保存了每一小格转了6度
canvas.save();
//画完大刻度就把大刻度的数字标一下(这里需要注意一下,需要数字朝向View的中心)
//开始移动坐标系到接近数字的地方
canvas.translate(radius + dp2px(30), 0);
//为了让数字的底部对着View的中心,所以canvas要顺时针转90度
canvas.rotate(90);
String str = String.valueOf(i / 5 + 1);
float strSize = mPaint.measureText(str);
canvas.drawText(str, -strSize / 2, 0, mTextPaint);
//回到//这时候坐标系 X轴在一点钟方向 Y轴在4点钟方向
canvas.restore();
} else {
//其他的情况下就是一个小格,所以画短刻度
canvas.drawLine(radius, 0, radius + dp2px(15), 0, mPaint);
}
//每画完一次刻度就顺时针转6度(也就是下一个刻度)
canvas.rotate(360 / 60f);
}
//这时候坐标系 X轴在三点钟方向 Y轴在六点钟方向
canvas.restore();
//箭头和线的颜色换成红色
mPaint.setColor(Color.RED);
//现在开始画箭头底下的线
canvas.drawLine(0, 0, 0, -radius + dp2px(3), mPaint);
Path path = new Path();
//画箭头
path.moveTo(-dp2px(3), -radius);//三角形左下角顶点
path.lineTo(dp2px(3), -radius);//三角形右下角顶点
path.lineTo(0, -radius - dp2px(3)); //顶点
path.close();
canvas.drawPath(path, mPaint);
//写文字
String MyText = "MyCanvasClock";
float MyTextSize = mTextPaint.measureText(MyText);
canvas.drawText(MyText, -MyTextSize / 2, dp2px(30), mTextPaint);
}
public int dp2px(int dp) {
return (int) (dp * mContext.getResources().getDisplayMetrics().density + 0.5f);
}
}
九.做个类似于芝麻信用分的实践
//步骤在代码中写(除了画等级分数之类,这个简单,可以参考上面的画钟)
public class MyView extends View {
//外围圆
private Paint outSideCirlePaint = new Paint();
//去掉下面的120
private Paint arc120Paint = new Paint();
//画大刻度的画笔
private Paint BigScalePaint = new Paint();
//画小刻度的画笔
private Paint smallScalePaint = new Paint();
//画中间的分数和信用等级
private Paint textPaint = new Paint();
//画进度条
private Paint processPaintBackGroud = new Paint();
private Paint processPaint = new Paint();
//画图片
private Paint bitmapPaint = new Paint();
private int viewWidth;
private int viewHeight;
private Context mContext;
private int outSideCriclePaintWidth;
private int innerSideCriclePaintWidth;
private int mCenterX;
private int mCenterY;
private int mRadius;
private String creditRand;
private float creditScore;
private Bitmap bitmapArrow;
private int mInnerSideRadius;
private float totalRotateAngle;
private boolean rotating = false;
private float rotateAngle;
private float currentAngle;
public interface setRotateAnlgleListener {
void setRotateAngle(int rotateAngle);
}
public MyView(Context context) {
super(context);
this.mContext = context;
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
init();
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
init();
}
private void init() {
initData();
initPaint();
}
private void initData() {
//最外面圆画笔的宽度
outSideCriclePaintWidth = CommonUtils.Dp2Px(mContext, 10);
innerSideCriclePaintWidth = CommonUtils.Dp2Px(mContext, 5);
//信用等级
creditRand = "信用等级";
//信用分数
creditScore = 350;
}
private void initPaint() {
//在外面的大圆画笔的设置
outSideCirlePaint.setAntiAlias(true);
outSideCirlePaint.setColor(Color.parseColor("#E0E0E0"));
outSideCirlePaint.setStrokeWidth(outSideCriclePaintWidth);
outSideCirlePaint.setStyle(Paint.Style.STROKE);
outSideCirlePaint.setAlpha(50);
//设置圆正下方152度去掉圆弧的画笔
arc120Paint.setAntiAlias(true);
arc120Paint.setColor(Color.parseColor("#9393FF"));
arc120Paint.setStyle(Paint.Style.FILL_AND_STROKE);
//初始化画大刻度的画笔
BigScalePaint.setAntiAlias(true);
BigScalePaint.setColor(Color.parseColor("#000000"));
BigScalePaint.setStyle(Paint.Style.STROKE);
BigScalePaint.setStrokeWidth(CommonUtils.Dp2Px(mContext, 2));
//初始化画小刻度的画笔
smallScalePaint.setAntiAlias(true);
smallScalePaint.setColor(Color.parseColor("#000000"));
smallScalePaint.setStyle(Paint.Style.STROKE);
smallScalePaint.setStrokeWidth(CommonUtils.Dp2Px(mContext, 1));
//初始化画字的画笔
textPaint.setAntiAlias(true);
textPaint.setColor(Color.parseColor("#ffffff"));
textPaint.setStyle(Paint.Style.STROKE);
textPaint.setTextSize(CommonUtils.Dp2Px(mContext, 20));
//进度条的画笔
processPaint.setAntiAlias(true);
processPaint.setColor(Color.parseColor("#00ff00"));
processPaint.setStyle(Paint.Style.STROKE);
processPaint.setStrokeWidth(innerSideCriclePaintWidth);
processPaintBackGroud.setAntiAlias(true);
processPaintBackGroud.setColor(Color.parseColor("#4DFFFF"));
processPaintBackGroud.setStyle(Paint.Style.STROKE);
processPaintBackGroud.setStrokeWidth(innerSideCriclePaintWidth);
//图片
bitmapPaint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//获取中心
mCenterX = getWidth() / 2;
mCenterY = getHeight() / 2;
mRadius = mCenterX - outSideCriclePaintWidth / 2;
//1.画出最外面的大圆
canvas.drawCircle(mCenterX, mCenterY, mRadius, outSideCirlePaint);
//2.把中心的移到view的中心
canvas.translate(mCenterX, mCenterY);
//3.然后画刻度 大的 小的(总共30个空格,240度,一格是八度,6格是一个大刻度)
//从右画到左
//(1)先把canvas先逆时针转 60
for (int i = 0; i < 31; i++) {
canvas.save();
canvas.rotate(-(60 + i * 8), 0, 0);
if (0 == i % 6) {
//6个空格画个大刻度
canvas.drawLine(0, mCenterX, 0, mRadius - CommonUtils.Dp2Px(mContext, 10), BigScalePaint);
} else {
//画个小刻度
canvas.drawLine(0, mCenterX, 0, mRadius - CommonUtils.Dp2Px(mContext, 5), smallScalePaint);
}
//还原到最开始的地方
//也就是坐标中心在view中心的时候 x y 水平竖直
canvas.restore();
}
//6.画信用等级
//7.画进度条//此时坐标轴的原点就在view中心
mInnerSideRadius = mCenterX - CommonUtils.Dp2Px(mContext, 20);
//进度条的背景
canvas.drawCircle(0, 0, mInnerSideRadius, processPaintBackGroud);
//进度条
RectF rectF = new RectF(-mInnerSideRadius, -mInnerSideRadius, mInnerSideRadius, mInnerSideRadius);
//-210 startAngle 120 sweepAngle
canvas.drawArc(rectF, -210, currentAngle, false, processPaint);
//8.去掉正下方的240度的圆弧
//现在view的中心的是(0,0)
clear120Arc(0, 0, canvas);
canvas.save();
//9.画出图片
bitmapArrow = BitmapFactory.decodeResource(getResources(), R.drawable.arrow);
canvas.rotate(-30+currentAngle);
Matrix matrix = new Matrix();
int bitmapWidth = bitmapArrow.getWidth();
int bitmapHeight = bitmapArrow.getHeight();
//这时候坐标系 已经逆时针偏转30度
matrix.preTranslate(-mInnerSideRadius - bitmapWidth * 3 / 8, -bitmapHeight / 2);
canvas.drawBitmap(bitmapArrow, matrix, bitmapPaint);
canvas.restore();
//4.画中间的字
float creditTextWidth = textPaint.measureText(creditRand);
canvas.drawText(creditRand, -creditTextWidth / 2, CommonUtils.Dp2Px(mContext, 50), textPaint);
//5.画中间的分数
float creditScoreWidth = textPaint.measureText(String.valueOf((int)creditScore));
canvas.drawText(String.valueOf((int)creditScore), -creditScoreWidth / 2, CommonUtils.Dp2Px(mContext, 30), textPaint);
}
/**
* 清除下面的120度的圆弧
*/
private void clear120Arc(int screenWithCenter, int screenHeighWidth, Canvas canvas) {
Point pointLeftBotton = new Point();
//设置左下角的点
pointLeftBotton.set(screenWithCenter - viewWidth / 2, screenHeighWidth + (int) ((viewWidth / 2) * Math.tan((Math.PI / 180) * 30)));
Point pointRightBotton = new Point();
//设置右下角的点
pointRightBotton.set(screenWithCenter + viewWidth / 2, screenHeighWidth + (int) ((viewWidth / 2) * Math.tan((Math.PI / 180) * 30)));
Path path = new Path();
// path.reset();
path.moveTo(screenWithCenter, screenHeighWidth);
path.lineTo(pointLeftBotton.x, pointLeftBotton.y);
path.lineTo(pointLeftBotton.x, screenHeighWidth + viewHeight / 2);
path.lineTo(pointRightBotton.x, screenHeighWidth + viewHeight / 2);
path.lineTo(pointRightBotton.x, pointRightBotton.y);
path.close();
System.out.println("xcqw screentWidthCenter-" + screenWithCenter + "-screenHeighWidth-" + screenHeighWidth);
System.out.println("xcqw pointLeftBotton-" + pointLeftBotton.x + "-pointLeftBotton.y-" + pointLeftBotton.y);
System.out.println("xcqw pointRightBotton-" + pointRightBotton.x + "-pointRightBotton.y-" + pointRightBotton.y);
canvas.drawPath(path, arc120Paint);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//获取view的宽度,高度
viewWidth = w;
viewHeight = h;
System.out.println("xcqw viewWidth-" + viewWidth + "-viewHeight-" + viewHeight);
}
public void setRotateAngle(int outcreditScore) {
System.out.println("xcqw setRotateAngle");
// if ( creditScore <= 350 ) {
// totalRotateAngle = 0f;
// } else if ( creditScore <= 550 ) {
// totalRotateAngle = ( creditScore - 150 ) * 80 / 400f ;
// } else if ( creditScore <= 700 ) {
// totalRotateAngle = ( creditScore - 550 ) * 120 / 150f + 80 ;
// } else if ( creditScore <= 950 ) {
// totalRotateAngle = ( creditScore - 700 ) * 40 / 250f + 200;
// } else {
// totalRotateAngle = 240f ;
// }
if (outcreditScore <= 350) {
totalRotateAngle = 0f;
} else if (outcreditScore <= 950) {
//总共240度 量程是350- 950分
totalRotateAngle = (outcreditScore - 350)/(600 / 240);
} else {
totalRotateAngle = 240f;
}
rotateAngle = totalRotateAngle / 60;
currentAngle = 0;
new Thread(new Runnable() {
@Override
public void run() {
rotating = true;
while (rotating) {
//箭头正在旋转
currentAngle += rotateAngle;
creditScore = (600/240)*currentAngle+350;
SystemClock.sleep(50);
if (currentAngle >= totalRotateAngle) {
currentAngle = totalRotateAngle;
rotating = false;
}
if (currentAngle >= 0 && currentAngle < 91) {
creditRand = "信用较差";
} else if (currentAngle > 90 && currentAngle < 151) {
creditRand = "信用良好";
} else if (currentAngle > 150) {
creditRand = "信用优秀";
}
postInvalidate();
}
}
}).start();
}
}
源码在这里