Android自定义控件基础

537 阅读5分钟

画笔基本属性

paint.isAntiAlias = true //打开抗锯齿

paint.style = Paint.Style.FILL //内部填充
paint.style = Paint.Style.FILL_AND_STROKE //内部填充和描边
paint.style = Paint.Style.STROKE //描边

paint.strokeWidth = 10f //描边宽度,只有style是FILL_AND_STROKE或者STROKE时有用

Canvas

画直线时直线的粗细和画笔的Style没有关系,和StrokeWidth有关系

drawRoundRect函数只能统一设置4个角对应的圆弧(椭圆)

drawCicle是画圆

drawOval是画椭圆

//弧
canvas?.drawArc(rect,0f,90f,true,paint)

drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,@NonNull Paint paint)

startAnngle是开始角度,X轴正方向为0度
sweepAngle是持续的角度
useCenter是否有弧两边,true为有,false为没有

Rect Rectf

contains(int x,int y)判断是否包含某个点

intersects(Rect a,Rect b)静态方法,判断两个矩形是否相交

intersect(Rect r)判断矩形是否相交

使用intersects时,只会判断是否相交,不会修改调用者Rect的值。当使用intersect来判断的时候,如果不相交,也不会修改值,但是如果相交,会把相交部分的矩形结果赋值给调用者。

union(Rect r)合并两个矩,合并的结果会返回给调用者

union(int x,int y)矩形和点合并

arcTo(RectF oval, float startAngle, float sweepAngle)弧型线路,弧型就是截取椭圆的一部分。Rectf就是生成椭圆的矩形。如果上一个点距离生成弧形的矩形很远,那么就会直线链接过来。 arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)forceMoveTo含义是是否强制讲弧形的起点作为绘制的起点

Path

moveTo(float x1,float y1)将点移动到(x1,y1)这个点,画直线,这里就是起始点

lineTo(float x2,float y2)直线的终点,下一个直线的起点

close()调用后会将路径的收尾点连接起来

addXXX函数

Path画出来的路径都是连贯的,我们通过addXXX函数可以直接往Path中添加曲线等,不用考虑连贯问题。这样就有可能出现中间空白的情况。 截屏2022-04-07 下午2.21.07.png

addRect(RectF rect,Path.Direction dir)Path.Direction参数有两个值.

  • Path.Direction.CCW:逆时针画
  • Path.Direction.CW:顺时针画 这个参数在画图的时候看不出来区别,但是在排版文字的时候可以用。

截屏2022-04-07 下午5.09.18.png

截屏2022-04-07 下午4.55.41.png

addRoundRect(RectF rect, float[] radii, Path.Direction dir)radii传入8个参数,分别是4个角的弧度

Path填充模式

Path.FillType是Path的填充模式

  • FillType.WINDING:默认,当两个图形相交时,取相交部分显示
  • FillType.EVEN_ODD:取Path所在并不相交的区域
  • FillType.INVERSE_WINDING:取Path的外部区域
  • FillType.INVERSE_EVEN_ODD:取Path的外部和相交区域

截屏2022-04-07 下午5.17.33.png

文字

截屏2022-04-08 上午10.04.48.png

Canvas绘制文本

截屏2022-04-08 上午10.15.02.png

根据Path绘制文字

截屏2022-04-08 下午2.41.11.png

设置字体

setTypeface(Typeface typeface)

当我们使用系统自带字体的时候Typeface类中保存了三个字体

  • Typeface.SANS_SERIF
  • Typeface.MONOSPACE
  • Typeface.SERIF 这三个字体对中文支持不好,所以一般中文是默认字体

defaultFromStyle(int style)

根据字体样式获取对应的字体,参数如下:

  • Typeface.NORMAL:正常字体
  • Typeface.BOLD:粗体
  • Typeface.ITALIC:斜体
  • Typeface.BOLD_ITALIC:粗斜体 如果使用的是宋体,那么BOLD获取出来的就是宋体的粗体

create(String familyName, int style) 通过字体名字返回系统中自带的字体样式,如果没有,返回默认字体

加载自定义字体

截屏2022-04-08 下午2.50.26.png 第一个方法可以从assets文件夹中获取字体,需要将字体放到assets文件夹的fonts文件夹下

Region

Region表示的是一个区域

普通构造方法,我们一般用第二三个

截屏2022-04-09 09.03.59.png

间接构造

截屏2022-04-09 09.04.34.png

例子:

截屏2022-04-09 09.06.49.png 取的是相交的部分。

RegionIterator:

对于特定区域,用足够小的矩形也能拼成差不多的模样,这个类就是获取特定区域中的矩形的。

构造方法:

RegionIterator(Region region)传入区域

获取矩形方法:

next(Rect r)会将获取的矩形赋值给r,该方法会返回一个Boolean值,可以用循环一直获取,直到为false

例子:

截屏2022-04-09 09.14.00.png

截屏2022-04-09 09.14.07.png

截屏2022-04-09 09.14.15.png

Region的主要功能是区域的相交操作

boolean union(Rect r)方法是合并传入的矩形区域,并取并集。

截屏2022-04-09 09.20.32.png 下面来一个例子,横着的矩形为主

截屏2022-04-09 10.16.16.png 也有第二个方法,传入两个区域,复制给调用的并没有赋值过的区域

截屏2022-04-09 10.18.26.png

其他函数:

截屏2022-04-09 10.25.38.png 截屏2022-04-09 10.25.47.png

Canvas

translate(float dx, float dy)平移,移动后坐标系也会移动,都是(0,0)这个点,加入x轴平移5个像素,那么真实的(5,0)就是canvas中的(0,0)

rotate(float degress)

rotate(float degress, float px, float py)

以上方法都是旋转动画,默认情况下是以原点为中心点选旋转的,旋转过后画出来的都是都是旋转后的。

scale(float sx,float sy)缩放,分别表示x,y轴的缩放,如果sx小于1,则是变小,如果sx大于1就是变大,默认也是已原点为缩放点

scale(float sx, float sy, float px, float py)后面两个参数可以指定缩放点。

skew(float sx, float sy)扭曲,参数分别表示在x,y轴上倾斜的相应角度,sx,sy为倾斜角度的正切值(倾斜60度,tan60 = 1.732)

例子:

截屏2022-04-11 07.35.22.png

画布剪裁是指用clip系列函数,通过与Rect,Path,Region取交,并,差等集合运算来获取新的画布形状。除了调用save(),restore()函数以外,这个操作是不可逆的,一旦Canvas被剪裁,就不能恢复了。

在使用clip系列函数需要禁用硬件加速。( setLayerType(LAYER_TYPE_SOFTWARE,null) )

截屏2022-04-11 07.40.16.png 例子:

截屏2022-04-11 07.40.52.png

前面讲的所有操作对画布都是不可逆的,如果操作过后忘记恢复就会造成一些麻烦。所以系统提供了与画布保存和回复相关的函数save(),restore()。 截屏2022-04-11 07.44.37.png 截屏2022-04-11 07.45.50.png

当多次调用save方法后会把画布的状态依次放入到一个栈中,每次调用restore都是取出最上面的一个画布状态,加入调用3次save,然后调用3次restore就会取出最开始存入的状态。

为了方便大家存在多次调用restore恢复画布的情况,还提供另一个函数,restoreToCount(int saveCount)。其实我们在调用save()方法后会返回一个int值,这个值保存的是当前保存的画布的一个索引,当调用restoreToCount方法的时候我们将这个索引传入,就会得到当时保存的画布状态。