Canvas VS Paint
Canvas方法
系统提供Canvas对象来提供绘图方法,其中Paint常见的属性如下:
mPaint.setAntiAlias() // 设置画笔的锯齿效果
mPaint.setColor() // 设置画笔的颜色
mPaint.setARGB() // 设置画笔的A、R、G、B值
mPaint.setAlpha() // 设置画笔的Alpha值
mPaint.setTextSize() // 设置字体的尺寸
mPaint.setStyle() // 设置画笔的风格(空心或实心)
mPaint.setStrokeWidth() // 设置空心边框的宽度
下面我们来看看Canvas一些简单的绘制:
// 绘制点
canvas.drawPoint(x, y, paint);
// 绘制直线
canvas.drawLine(startX, startY, stopX, stopY, paint);
// 绘制多条直线
float[] pts = {
startX1, startY1, endX1, endY1,
......
startXn, startYn, endXn, endYn};
canvas.drawLines(pts, paint);
// 绘制矩形
canvas.drawRect(left, top, right, bottom, paint);
// 绘制圆角矩形
canvas.drawRoundRect(left, top, right, bottom, rx, ry, paint);
// 绘制圆
canvas.drawCircle(cx, cy, radius, paint);
// 绘制弧线,这里需要注意绘制弧线和扇形的区分就是倒数第二个参数useCenter的值,true或false。
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint);
// 绘制椭圆
canvas.drawOval(left, top, right, bottom, paint);
// 绘制文本
canvas.drawText(text, x, y, paint);
// 在指定位置绘制文本
canvas.drawPosText(text,
new float[]{
X1, Y1,
......
Xn, Yn}, paint);
// 绘制路径
Path path = new Path();
path.moveTo(50, 50);
path.lineTo(100, 100);
path.lineTo(100, 300);
canvas.drawPath(path, mPaint);
Canvas实例
Canvas作为绘制图像的直接对象,提供以下几个非常有用的方法:
Canvas.save(): 保存画布,将之前所有已经绘制的图像保存起来,让后续操作在新的图层上操作。
Canvas.restore() 合并图层操作,它的作用是将save()之后绘制的所有图像与save()之前的图像进行合并。
Canvas.translate() 和 Canvas.rotate():画布的坐标系的翻转和偏移。
绘制仪表盘实例
- 仪表盘 --- 外面的大圆盘
- 刻度线 --- 包含四个长的刻度线和其他短的刻度线
- 刻度值 --- 包含长刻度线对应的大的刻度值和其他小的刻度值
- 指针 --- 中间的指针,一粗一细两根指针
public class KeDuPanView extends View {
private int mWidth;
private int mHeight;
public KeDuPanView(Context context) {
this(context, null);
}
public KeDuPanView(Context context, AttributeSet attrs) {
super(context, attrs);
WindowManager wManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mWidth = wManager.getDefaultDisplay().getWidth();
mHeight = wManager.getDefaultDisplay().getHeight();
}
@Override
protected void onDraw(Canvas canvas) {
// 画外圆
Paint paintCircle = new Paint();
paintCircle.setStyle(Paint.Style.STROKE);
paintCircle.setAntiAlias(true);
paintCircle.setStrokeWidth(5);
canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, paintCircle);
// 画刻度
Paint paintDegree = new Paint();
paintDegree.setStrokeWidth(3);
for (int i = 0; i < 24; i++) {
// 区分整点和非整点
if(i == 0 || i== 6 || i == 12 || i == 18){
paintDegree.setStrokeWidth(5);
paintDegree.setTextSize(18);
// 画长刻度
canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2,
mWidth / 2, mHeight / 2 - mWidth / 2 + 30, paintDegree);
// 画数字
String degree = String.valueOf(i);
canvas.drawText(degree, mWidth / 2 - paintDegree.measureText(degree) / 2,
mHeight / 2 - mWidth / 2 + 45, paintDegree);
}else{
// 画短刻度
paintDegree.setStrokeWidth(3);
paintDegree.setTextSize(15);
canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2, mWidth / 2,
mHeight / 2 - mWidth / 2 + 15, paintDegree);
// 画数字
String degree = String.valueOf(i);
canvas.drawText(degree, mWidth / 2 - paintDegree.measureText(degree) / 2,
mHeight / 2 - mWidth / 2 + 30, paintDegree);
}
// 通过旋转画布简化坐标运算
canvas.rotate(15, mWidth / 2, mHeight / 2);
}
// 画中间指针,时针和分针
Paint paintHour = new Paint();
paintHour.setStrokeWidth(10);
Paint paintMinute = new Paint();
paintMinute.setStrokeWidth(5);
canvas.save();
// 开始位置移动到屏幕中心点
canvas.translate(mWidth / 2, mHeight / 2);
canvas.drawLine(0, 0, 50, 50, paintHour);
canvas.drawLine(0, 0, 50, 100, paintMinute);
canvas.restore();
}
}
绘制螺旋图
绘制螺旋图可以主要是掌握绘制圆弧的API,实现效果如下:
代码如下所示:
public class PieCharView extends View {
private Paint mPaint = new Paint();
private Paint mTextPaint = new Paint();
private int mRadius;
private int mWidth;
private int mHeight;
// 绘制不规则扇形
private int offset; // 中心点偏移坐标
private int startAngle = -180;
private int decrement = 50;
private String[] mColors = new String[]{"#00A200", "#FF7A29", "#F1B766", "#FFBD99", "#008A96", "#E75A41"};
private int[] mAngles = new int[]{120, 60, 45, 30, 20, 85};
public PieCharView(Context context) {
this(context, null);
}
public PieCharView(Context context, AttributeSet attrs) {
super(context, attrs);
// 设置扇形画笔
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
// 设置文字画笔
mTextPaint.setColor(Color.parseColor("#794C3D27"));
mTextPaint.setAntiAlias(true);
mTextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mTextPaint.setTextAlign(Paint.Align.CENTER);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
}
@Override
protected void onDraw(Canvas canvas) {
mRadius = (mWidth + mHeight) / 2;
for (int i = 0; i <= 5; i ++){
mPaint.setColor(Color.parseColor(mColors[i]));
RectF rectF = new RectF(0, 0, mRadius, mRadius);
offset = (decrement / 2) * i;
rectF.offset(offset, offset);
int angle = mAngles[i];
canvas.drawArc(rectF, startAngle, angle, true, mPaint);
mRadius = mRadius - decrement;
startAngle = startAngle + angle;
}
// 绘制中心圆
mPaint.reset();
mPaint.setColor(Color.parseColor("#FFFFFF"));
mRadius = mRadius - decrement;
canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius / 2, mPaint);
// 绘制中心文字
mTextPaint.setTextSize(45);
String text = "总入住";
Rect rect = new Rect();
mTextPaint.getTextBounds(text, 0, text.length() - 1, rect); // 测量文字高度
int textHeight = rect.height();
canvas.drawText("总入住", mWidth / 2, mHeight / 2 - (textHeight / 2), mTextPaint);
mTextPaint.setTextSize(51);
mTextPaint.setColor(Color.parseColor("#009E1F"));
canvas.drawText("500 间", mWidth / 2, mHeight / 2 + (textHeight / 2) + 10, mTextPaint);
}
/**测量宽度的代码*/
private int measureWidth(int measureSpec){
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if(specMode == MeasureSpec.EXACTLY){
result = specSize;
}else{
result = 300;
if(specMode == MeasureSpec.AT_MOST){
result = Math.min(result, specSize);
}
}
return result;
}
/**测量高度的代码*/
private int measureHeight(int measureSpec){
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if(specMode == MeasureSpec.EXACTLY){
result = specSize;
}else{
result = 300;
if(specMode == MeasureSpec.AT_MOST){
result = Math.min(result, specSize);
}
}
return result;
}
}