您的位置:首页 > 其它

自定义View之自绘控件-绘制基础

2017-07-12 15:39 288 查看
这篇文章来回顾一下自定义view这一块的基础知识,首先我们来明确几个问题:

什么是自定义view

Android所有的控件都是View或者View的子类,它其实表示的就是屏幕上的一块矩形区域,用一个Rect来表示,left,top表示View相对于它的parent View的起点,width,height表示View自己的宽高,通过这4个字段就能确定View在屏幕上的位置,确定位置后就可以开始绘制View的内容了。

总结来说,自定义View的实现有三种方式,分别是:组合控件、自绘控件和继承控件。

这篇文章接下来要讲的就是自绘控件

自定义view有什么用,使用的场景是什么?

虽然Android内置了许多View供开发者组合和使用,但其多样性还是不足,在很多场景或功能需求下,Android原生自带的控件并不足以实现需求,这时我们就需要自定义满足我们需求的View。

View绘制过程

View的绘制可以分为下面三个过程:

Measure

View会先做一次测量,算出自己需要占用多大的面积。View的Measure过程给我们暴露了一个接口onMeasure,方法的定义是这样的,

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {}


View类已经提供了一个基本的onMeasure实现,

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);

switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}


其中invoke了setMeasuredDimension()方法,设置了measure过程中View的宽高,getSuggestedMinimumWidth()返回View的最小Width,Height也有对应的方法。插几句,MeasureSpec类是View类的一个内部静态类,它定义了三个常量UNSPECIFIED、AT_MOST、EXACTLY,其实我们可以这样理解它,它们分别对应LayoutParams中match_parent、wrap_content、xxxdp。我们可以重写onMeasure来重新定义View的宽高。

Layout

Layout过程对于View类非常简单,同样View给我们暴露了onLayout方法

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}


因为我们现在讨论的是View,没有子View需要排列,所以这一步其实我们不需要做额外的工作。插一句,对ViewGroup类,onLayout方法中,我们需要将所有子View的大小宽高设置好,这个我们下一篇会详细说。

Draw

Draw过程,就是在canvas上画出我们需要的View样式。同样View给我们暴露了onDraw方法

protected void onDraw(Canvas canvas) {
}


默认View类的onDraw没有一行代码,但是提供给我们了一张空白的画布,举个例子,就像一张画卷一样,我们就是画家,能画出什么样的效果,完全取决我们。

如何自定义view

在实现以下需求之前,首先要创建一个view的子类,

example:

public class CustomView extends View {

public CustomView(Context context) {
this(context,null);
}

public CustomView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}

public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context,attrs,defStyleAttr);

}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

}
}


我们接下来的操作将都在onDraw方法里面实现

这里我们有两个类要了解下:

Canvas

Canvas类就是表示一块画布,你可以在上面画你想画的东西。当然,你还可以设置画布的属性,如画布的颜色/尺寸等

Paint

Paint类代表画笔,用来描述图形的颜色和风格,如线宽,颜色,透明度,和填充效果等信息,使用Paint时,需要先创建该类的对象,这可以通过该类提供的构造方法来实现。通常情况下,只需要使用无参数的构造方法来创建一个使用默认设置的Paint对象:

Panit paint=new Panint();


绘制几何图形

画圆

canvas.drawCircle(300,300,200,paint);//前两个参数 centerX centerY 是圆心的坐标,第三个参数 radius 是圆的半径,单位都是像素,它们共同构成了这个圆的基本信息


画矩形

canvas.drawRect(100,500,500,800,paint);//前面四个参数依次为左、上、右、下四条边的坐标位置


画椭圆

canvas.drawOval(100,500,500,700,paint);


画扇形

canvas.drawArc(200, 100, 800, 500, -80, -100, true, paint);


画弧

paint.setStyle(Paint.Style.STROKE);//只描边
canvas.drawArc(200, 100, 800, 500, 20, 140, false,paint); // 绘制弧形


绘制文本

// 参数text:要绘制的文本
// 参数x,y:指定文本开始的位置(坐标)
// 参数paint:设置的画笔属性
public void drawText (String text, float x, float y, Paint paint)

// 仅绘制文本的一部分
// 参数start,end:指定绘制文本的位置
// 位置以下标标识,由0开始
public void drawText (String text, int start, int end, float x, float y, Paint paint)
public void drawText (CharSequence text, int start, int end, float x, float y, Paint paint)

// 对于字符数组char[]
// 截取文本使用起始位置(index)和长度(count)
public void drawText (char[] text, int index, int count, float x, float y, Paint paint)


绘制图片

绘制图片分为:绘制矢量图(drawPicture)和 绘制位图(drawBitmap)

绘制矢量图(drawPicture)

作用:绘制矢量图的内容,即绘制存储在矢量图里某个时刻Canvas绘制内容的操作

矢量图(Picture)的作用:存储(录制)某个时刻Canvas绘制内容的操作

应用场景:绘制之前绘制过的内容

1. 相比于再次调用各种绘图API,使用Picture能节省操作 & 时间

2. 如果不手动调用,录制的内容不会显示在屏幕上,只是存储起来

特别注意:使用绘制矢量图时前请关闭硬件加速,以免引起不必要的问题!

绘制位图(drawBitmap)

作用:将已有的图片转换为位图(Bitmap),最后再绘制到Canvas上

位图,即平时我们使用的图片资源

绘制路径

// 通过传入具体路径Path对象 & 画笔
canvas.drawPath(mPath, mPaint)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐