(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,这个宽度是半径内一半,半径外一半)
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);/**
canvas.translate(getWidth() / 2, getHeight() / 2);
//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); } }
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); } }
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);/**
//-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); } }
我觉得最难理解就是这个矩形跟圆的关系,下面就是他们之间的关系!!!
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度,画布本身没有转
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(); } }
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是相对他的容器
@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); }
@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>的效果都是一样的如下图
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(); } }源码在这里