1. View 的绘制
完成了View
的测量后,根据拿到的View的大小,位置,重写onDraw(Canvas canvas)
就可以进行绘制。
现实中,如果想要画一幅画,必须要有画笔和画布。Canvas
就是画布,Paint
就是画笔。Canvas和Patint有各种各样的属性。本篇先学习部分常用的基础的属性,一些可以高度化定制的属性后续再进行学习。
2. Canvas
想要画出一个View
就必须要有4个必要的元素:
- 保存像素的Bitmap
- 管理绘制请求的Canvas
- 绘画的原始基本元素,例如矩形,线,文字,Bitmap
- 拥有颜色和风格信息的画笔
Canvas
有两种常见创建方法:
Canvas canvas = new Canvas()
空参构造方法
Canvas canvas = new Canvas(bitmap)
创建一个装载画布。构造方法中传入的bitmap存储所有绘制在canvas的信息。
常用的几个绘制方法
方法 | 作用 |
---|---|
drawRect() |
画矩形 |
drawCircle() |
画圆 |
zdrawArc() |
画圆弧 |
drawRoundRect() |
画圆角矩形 |
drawBitmap() |
画一个Bitmap |
drawOval() |
画椭圆 |
drawText() |
画文字 |
2.1drawRect()
drawRect()
有三种重载方法:
drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)
drawRect(@NonNull Rect r, @NonNull Paint paint)
-
drawRect(@NonNull RectF r, @NonNull Paint paint)
两个方法的差别在于Rect和RectF的差别:Rect 坐标为integer
而RectF 坐标为float
MeausreView代码,主要绘制就是onDraw()
方法:
public class MeasureView extends View {
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
public MeasureView(Context context) {
super(context);
initPaint();
}
public MeasureView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
}
public MeasureView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec), measuredHeight(heightMeasureSpec));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float left = getLeft();
float right = getRight();
float top = getTop();
float bottom = getBottom();
canvas.drawRect(left,top,right,bottom,paint); // 绘制矩形
// Rect rect = new RectF(100,100,200,200);
// canvas.drawRect(rect,paint);
// RectF rect = new RectF(100.5f,100.5f,200.5f,200.5f);
// canvas.drawRect(rect,paint);
}
/**
* 测量宽
*
* @param widthMeasureSpec
*/
private int measureWidth(int widthMeasureSpec) {
int result;
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = 200;
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
/**
* 测量高
*
* @param heightMeasureSpec
*/
private int measuredHeight(int heightMeasureSpec) {
int result;
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = 200;
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
private void initPaint() {
paint.setColor(Color.parseColor("#FF4081"));
}
}
MeausureView 的 width = right - left
MeausureView 的 height = bottom - top
在Activity
的布局文件中:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.szlk.customview.custom.MeasureView
android:id="@+id/mv_custom_activity"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="@color/colorPrimary" />
</LinearLayout>
2.2 drawCricle() 绘制圆形
-
drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
radius
: 半径
cx
: 圆心的x坐标
cy
: 圆心的y坐标
使用的时候需要考虑圆心和半径
使用:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float width = getWidth();
float height = getHeight();
float radius = Math.max(width,height)/2; //绘制圆形时,半径是宽和高中较大者的二分之一
Log.d("MeasureView", "onDraw: "+(radius));
canvas.drawCircle(width/2, height/2, radius, paint);
}
2.3 drawArc() 绘制扇形
两种构造方法:
drawArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean useCenter, @NonNull Paint paint)
drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint)
两种方法的区别:
- 方法2把坐标封装进
RectF
对象中 - 方法1要求系统最低为21
-
float startAngle
开始绘制的角度 -
float sweepAngle
扇形扫过的角度,并不是停止时的角度。停止角度 = startAngle+ sweepAngle -
boolean useCenter ture
就是有焦点圆心 , false 没有
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
RectF rect = new RectF(0f,0f,500f,500f);
canvas.drawArc(rect,0,60,false,paint);
canvas.drawArc(rect,60,30,true,paint2);
}
2.4 drawBitmap() 绘制Bitmap
drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint)
-
left
左上角横坐标 -
top
左上角纵坐标
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
float width = (getWidth()-bitmap.getWidth())/2;
float height = (getHeight()-bitmap.getHeight())/2;
canvas.drawBitmap(bitmap,width,height,paint);
}
2.5 drawText()绘制文字
drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText("HelloWorld",100,100,paint);
}
2.6 drawPath()路径
drawPath()
-
moveTo()
就是绘制的起始点,默认为(0,9) -
lineTo()
连接的点
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Path p = new Path();
p.moveTo(100, 100);
p.lineTo(200, 50);
p.lineTo(300, 100);
p.lineTo(200,400);
canvas.drawPath(p,paint);
}
3. Paint
画笔能够拿到,所要绘制的几何图形、文字或者Bitmap的颜色、风格等信息
画笔有三种构造方法:
-
public Paint() { this(0); }
创建一个默认属性的画笔 -
public Paint(int flags) {...}
创建一个带有标记的画笔。也可以通过setFlags()去为一个已经创建过的画笔设置标签 -
public Paint(Paint paint) {...}
通过一个已经配置好信息的画笔来创建一个新的画笔
3.1常用属性方法
- 绘制文字
方法 | 作用 |
---|---|
setColor(@ColorInt int color) |
设置画笔颜色 |
setStrokeWidth(float width) |
设置画笔粗细 |
setTextSkewX(float f) |
设置倾斜,负右斜,正为左 |
setARGB(int a,int r,int g,int b) |
设置颜色,a为透明度 |
setTextSize(float textSize) |
设置绘制文字大小 |
setFakeBoldText(boolean fakeBoldText) |
是否粗体 |
setTextAlign(Paint.Align align) |
设置文字对齐方式,LEFT,CENTER,RIGHT |
setUnderlineText(boolean underlineText) |
设置下划线 |
setStyle(Style style) |
设置画笔样式,FILL,STROKE,FILL_AND_STROKE |
setTypeface(Typeface typeface) |
设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等 |
- 绘制图像
方法 | 作用 |
---|---|
setDither(boolean dither) |
设置抖动处理 |
setAlpha(int a) |
设置透明度 |
setAntiAlias(boolean aa) |
是否开启抗锯齿 |
setFilterBitmap() |
是否开启优化Bitmap |
setColorFilter(ColorFilter filter) |
设置颜色过滤 |
setMaskFilter(MaskFilter maskfilter) |
设置滤镜的效果 |
setShader(Shader shader) |
设置图像渐变效果 |
setSrokeJoin(Paint.Join join) |
设置图像结合方式 |
setXfermode(Xfermode xfermode) |
设置图像重叠效果 |
setPathEffect(PathEffect effect) |
设置路径效果 |
reset() |
恢复默认设置 |
注意:onDraw()
方法中,最好不要进行new对象。