Android自定义View-绘图进阶

379 阅读5分钟

贝塞尔曲线

一阶贝塞尔曲线

简单理解一阶贝塞尔曲线就是从起点到终点的直线

二阶贝塞尔曲线

二阶贝塞尔曲线其实是由两个一阶贝塞尔曲线构成,他们之间的移动点又构成了一个贝塞尔曲线,而这个贝塞尔曲线的移动点的路径就是二阶贝塞尔曲线。

1651643178055.jpg 图中Q0Q1就是形成的一阶贝塞尔曲线,点B的轨迹就是二阶贝塞尔曲线。

三阶贝塞尔曲线

三阶贝塞尔曲线和二阶贝塞尔曲线同理,只不过多了一个点。

1651643342287.jpg 点B的轨迹就是三阶贝塞尔曲线。

在Android中并没有四阶,五阶贝塞尔曲线的方法,这里就不讨论了。

在Android中有四个方法和贝塞尔曲线有关:

//二阶贝塞尔
public void quadTo(float x1, float y1, float x2, float y2)

public void rQuadTo(float dx1, float dy1, float dx2, float dy2)

//三阶贝塞尔
public void cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)

public void rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3)

quadTo函数中x1和y1是控制点的坐标,x2和y2是终点坐标。在Path中如果没有指定起始点,那么(0,0)就是起始点。

rQuadTo这个方法中四个参数和quadTo不一样,他们都是相对坐标

  • dx1:控制点X轴坐标,相对于上一个终点的位移坐标,可以为负数
  • dy1:控制点Y轴坐标,相对于上一个终点的位移坐标,可以为负数
  • dx2:终点X轴坐标,相对于上一个终点的位移坐标,可以为负数
  • dy2:终点Y轴坐标,相对于上一个终点的位移坐标,可以为负数

阴影

public void setShadowLayer(float radius, float dx, float dy, @ColorInt int shadowColor)

给画笔设置阴影的函数

  • radius:模糊半径,值越大,阴影越模糊
  • dx,dy:偏移距离
  • shadowColor:阴影颜色 用以上方法给图片加阴影的时候,系统会以图片的颜色来设置阴影,而不是统一颜色。

在绘制阴影的时候只有文字绘制阴影可以使用硬件加速,所以建议自定义控件中禁用硬件加速。

阴影模糊是只模糊边界部分,随着radius值越来越大,慢慢向中间模糊。

调用clearShadowLayer()可以清除阴影,将radius设置成0也可以清除阴影。

我们也可以给TextView和它的派生控件添加阴影

在XMl中添加阴影

<TextView
    android:shadowRadius = "3"
    android:shadowDx = "4"
    android:shadowDy = "4"
    android:shadowColor = "#000000"/>

上面几个方法对应上面方法的几个参数。

也可以通过代码给控件设置

tv.setShadowLayer(2,5,5,Color.GRAY)

光效,图片阴影

发光效果和阴影效果差不多,都是边缘模糊,都是用的高斯模糊算法。发光的颜色是边缘部分的颜色取样,所以边缘是什么颜色,发光就是什么颜色。

public MaskFilter setMaskFilter(MaskFilter maskfilter)

该方法也不支持硬件加速。

传入的MaskFilter有两个派生类:

  • BlurMaskFilter:发光效果
  • EmbossMaskFilter:浮雕效果(使用很少)

BlurMaskFilter

public Blur.INNER,(float radius, Blur style)

生成BlurMaskFilter的时候会传入两个参数

  • radius:模糊半径
  • style:发光样式。Blur.INNER(内发光),Blur.SOLID(外发光),Blur.NORMAL(内外发光),Blur.OUTER(仅显示发光效果)

1651653251800.jpg 仅显示发光效果是除了发光的部分都变成透明的。

我们在绘制图片阴影的时候,可以先用Bitmap的extractAlpha方法获取一个只有alpha值,大小一样的Bitmap,这样画笔是什么颜色,画出来的新Bitmap就是什么颜色,然后将画笔设置BlurMaskFilter使画出来的图像有发光效果。最后在画一个原图上去,就给图片设置了指定颜色的阴影。

Shader、BitmapShader

Paint调用setShader方法来设置Shader

public Shader setShader(Shader shader)

Shader有一些派生类,它自己并没有实现。

BitmapShader

public BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)
  • bitmap:指定图案
  • tileX:指定当X轴超出单张图片大小后使用的重复策略
  • tileY:指定当Y轴超出单张图片大小后使用的重复策略 TileMode的取值如下:
  • TileMode.CLAMP:用边缘色彩填充多余空间
  • TileMode.REPEAT:重复原图来填充
  • TileMode.MIRROR:重复使用镜像来填充

使用Shader进行绘制的时候,Shader总是从控件左上角开始,我们绘制所看到的只是图像该位置的显示出来了其他地方没有显示出来。

1651654305592.jpg

LinearGradient

通过LinearGradient实现线性渐变效果。

LinearGradient有两个构造函数:

public LinearGradient(float x0, float y0, float x1, float y1, @ColorInt int color0, @ColorInt int color1, @NonNull TileMode tile)

public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int[] colors, @Nullable float[] positions, @NonNull TileMode tile)

第一个构造函数中x0和y0是渐变起始点坐标,x1,y1是渐变终点坐标,color0和color1是渐变的两个颜色,TileMode是模式。第一个构造函数只支持两个颜色的渐变。

第二个构造函数支持多个颜色之间的渐变,colors可以传入多个颜色,positions与渐变的颜色对应,取值0~1的Float类型,表示每个颜色在渐变中的百分比。加入有4个颜色,那么每一个positions对应的指就是颜色从左往右的占比,我们设置四个值分别是0.0,0.2,0.4,1.0,那么0到0.2就是第一个和第二个颜色,0.2到0.4是第二个和第三个颜色,0.4到1.0是第三个和第四个颜色。

RadialGradient

放射渐变

public RadialGradient(float centerX, float centerY, float radius, @ColorInt int centerColor, @ColorInt int edgeColor, @NonNull TileMode tileMode)
  • centerX和centerY是渐变中心点坐标
  • radiius是渐变半径
  • centerColor是起始颜色,渐变中心点的颜色,必须要8位ARGB,否则不显示
  • edgeColor是渐变结束的颜色,也要8位
  • tileMode就是超出范围后的填充模式

多个颜色渐变:

public RadialGradient(float centerX, float centerY, float radius, @NonNull @ColorInt int[] colors, @Nullable float[] stops, @NonNull TileMode tileMode)
  • colors是多个颜色
  • stops对应颜色,范围是0~1