如何成为自定义高手(一)绘制

其实这边并不需要你记住太多,能有知道有这样的作用,让后不会使用的时候当工具来查看就看。主要是需要能灵活运用这些。下面我来介绍一下:

1. 绘画基础

这篇文章很基础,罗列一下文章中提到的绘制方法。对于一些重点和大家不太了解的,我会斜体加粗。

Paint 类的几个最常用的方法。具体是:
  • Paint.setStyle(Style style) 设置绘制模式
  • Paint.setColor(int color) 设置颜色
  • Paint.setStrokeWidth(float width) 设置线条宽度
  • Paint.setTextSize(float textSize) 设置文字大小
  • Paint.setAntiAlias(boolean aa) 设置抗锯齿开关
  • Paint.setStrokeCap(cap) 设置点的形状
Canvas 类下相关的方法:
  • Canvas.drawColor(@ColorInt int color) ,Canvas.drawRGB(int r, int g, int b) ,Canvas.drawARGB(int a, int r, int g, int b) 颜色填充
  • Canvas.drawCircle(float centerX, float centerY, float radius, Paint paint) 画圆
  • Canvas.drawRect(float left, float top, float right, float bottom, Paint paint),Canvas.drawRect(RectF rect, Paint paint) ,Canvas.drawRect(Rect rect, Paint paint) 画矩形
  • Canvas.drawPoint(float x, float y, Paint paint) 画点
  • Canvas.drawPoints(float[] pts, int offset, int count, Paint paint),Canvas.drawPoints(float[] pts, Paint paint) 画点(批量)
  • Canvas.drawOval(float left, float top, float right, float bottom, Paint paint),Canvas.drawOval(RectF rect, Paint paint)画椭圆
  • Canvas.drawLine(float startX, float startY, float stopX, float stopY, Paint paint) 画线
  • Canvas.drawLines(float[] pts, int offset, int count, Paint paint),Canvas.drawLines(float[] pts, Paint paint) 画线(批量)
  • Canvas.drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint) 画圆角矩形
  • Canvas.drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint) 绘制弧形或扇形
  • Canvas.drawBitmap(Bitmap bitmap, float left, float top, Paint paint),Canvas.drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint),Canvas.drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint), Canvas.drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)画 Bitmap
  • Canvas.drawText(String text, float x, float y, Paint paint) 绘制文字
  • Canvas.drawPath(Path path, Paint paint) 画自定义图形,一般复杂图形都会用到这个。
Path 方法:
  • Path.addCircle(float x, float y, float radius, Direction dir) 添加圆
  • Path.addOval(float left, float top, float right, float bottom, Direction dir) / addOval(RectF oval, Direction dir) 添加椭圆
  • Path.addRect(float left, float top, float right, float bottom, Direction dir) / addRect(RectF rect, Direction dir) 添加矩形
  • Path.addRoundRect(RectF rect, float rx, float ry, Direction dir) / addRoundRect(float left, float top, float right, float bottom, float rx, float ry, Direction dir) / addRoundRect(RectF rect, float[] radii, Direction dir) / addRoundRect(float left, float top, float right, float bottom, float[] radii, Direction dir) 添加圆角矩形
  • Path.addPath(Path path) 添加另一个 Path
  • Path.lineTo(float x, float y) / rLineTo(float x, float y) 画直线,第二个是相对坐标
  • Path.quadTo(float x1, float y1, float x2, float y2) / rQuadTo(float dx1, float dy1, float dx2, float dy2) 画二次贝塞尔曲线
  • Path.cubicTo(float x1, float y1, float x2, float y2, float x3, float y3) / rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3) 画三次贝塞尔曲线
  • Path.moveTo(float x, float y) / rMoveTo(float x, float y) 移动到目标位置
  • Path.arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) / arcTo(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo) / arcTo(RectF oval, float startAngle, float sweepAngle) 画弧形,forceMoveTo=true没有痕迹,false有痕迹
  • Path.addArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle) / addArc(RectF oval, float startAngle, float sweepAngle) 添加弧形
  • Path.close() 封闭当前子图形
  • Path.setFillType(Path.FillType ft) 设置填充方式,WINGING(不考虑图形绘制方向)交点偶数为外部,交点奇数为内部,EVEN_ODD(考虑绘制图形方向)交点为0是外部,交点不为零为内部,内部填充颜色。
    自定义View绘制基础

2. 详解Paint

设置颜色:
  • setShader(Shader shader) 设置 着色器Shader,Shader一共有5种
    LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile) 线性渐变,TileMode 一共有 3 个值可选: CLAMP, MIRROR 和 REPEAT
    RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode) 辐射渐变
    SweepGradient(float cx, float cy, int color0, int color1) 扫描渐变
    BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
    ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) 混合着色器

  • setColorFilter(ColorFilter colorFilter) 为绘制设置颜色过滤,使用LightingColorFilter PorterDuffColorFilter 和 ColorMatrixColorFilter
    LightingColorFilter(int mul, int add) mul用来和目标像素相乘,add用来和目标像素相加
    PorterDuffColorFilter(int color, PorterDuff.Mode mode)
    ColorMatrix(new float[]{}); 4*5的矩阵,具体效果自己网上查找

  • setXfermode(Xfermode xfermode) 以绘制的内容作为源图像,以 View 中已有的内容作为目标图像,选取一个 PorterDuff.Mode 作为绘制内容的颜色处理方案
    使用离屏缓存(View自身的底并不是透明,结合后容易出现周边黑色的问题)
    控制它的透明区域不要太小,要让它足够覆盖到要和它结合绘制的内容

    如何成为自定义高手(一)绘制_第1张图片
    SRC源图像和DST目标图像.png

如何成为自定义高手(一)绘制_第2张图片
PorterDuff Alpha合成.png

如何成为自定义高手(一)绘制_第3张图片
混合.png
效果:
  • setAntiAlias (boolean aa) 设置抗锯齿
  • setStyle(Paint.Style style) 设置图形是线条风格还是填充风格的(也可以二者并用)
  • setStrokeWidth(float width) 设置线条宽度。
  • setStrokeCap(Paint.Cap cap) 设置线头的形状
  • setStrokeJoin(Paint.Join join) 设置拐角的形状,MITER 尖角、 BEVEL 平角和 ROUND 圆角
  • setStrokeMiter(float miter) setStrokeJoin() 的一个补充,它用于设置 MITER 型拐角的延长线的最大值。
  • setDither(boolean dither) 设置图像的抖动
  • setFilterBitmap(boolean filter) 设置是否使用双线性过滤来绘制 Bitmap
  • setPathEffect(PathEffect effect) PathEffect 分为两类,
    单一效果的CornerPathEffect(float radius)(把所有拐角变成圆角) ,
    DiscretePathEffect(float segmentLength, float deviation)(把线条进行随机的偏离) ,
    DashPathEffect(float[] intervals, float phase)(使用虚线来绘制线条),
    PathDashPathEffect(Path shape, float advance, float phase, PathDashPathEffect.Style style)(它是使用一个 Path 来绘制「虚线」) ,
    组合效果的 SumPathEffect(不同效果,画多次)
    ComposePathEffect(不同效果先组合,画一次)。
  • setShadowLayer(float radius, float dx, float dy, int shadowColor) 在之后的绘制内容下面加一层阴影
  • setMaskFilter(MaskFilter maskfilter) 设置的是在绘制层上方的附加效果
    BlurMaskFilter(float radius, BlurMaskFilter.Blur style) 模糊效果的 MaskFilter。Blur style:NORMAL(内外都模糊绘制),SOLID(内部正常绘制,外部模糊),INNER(内部模糊,外部不绘制),OUTER(内部不绘制,外部模糊)
  • EmbossMaskFilter(float[] direction, float ambient, float specular, float blurRadius) 浮雕效果的 MaskFilter。
  • getFillPath(Path src, Path dst)
  • getTextPath(String text, int start, int end, float x, float y, Path path) / getTextPath(char[] text, int index, int count, float x, float y, Path path)
初始化
  • reset()
  • set(Paint src)
  • setFlags(int flags)
    自定义view Paint 详解

3.文字的绘制

Canvas 绘制文字的方式
  • drawText(String text, float x, float y, Paint paint) 参数x,y一个与左下角比较接近的位置,y是文字的基线
  • drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) 沿着一条 Path 来绘制文字。hOffset 和 vOffset,分别是文字相对于 Path 的水平偏移量和竖直偏移量
  • StaticLayout(CharSequence source, TextPaint paint, int width, Layout.Alignment align, float spacingmult, float spacingadd, boolean includepad)支持换行,它既可以为文字设置宽度上限来让文字自动换行,也会在 \n 处主动换行。
    width 是文字区域的宽度,文字到达这个宽度后就会自动换行;
    align 是文字的对齐方向;
    spacingmult 是行间距的倍数,通常情况下填 1 就好;
    spacingadd 是行间距的额外增加值,通常情况下填 0 就好;
    includeadd 是指是否在文字上下添加额外的空间,来避免某些过高的字符的绘制出现越界
设置显示效果类
  • setTextSize(float textSize) 设置文字大小
  • setTypeface(Typeface typeface) 设置字体
  • setFakeBoldText(boolean fakeBoldText) 是否使用伪粗体
  • setStrikeThruText(boolean strikeThruText) 是否加删除线
  • setUnderlineText(boolean underlineText) 是否加下划线
  • setTextSkewX(float skewX) 设置文字横向错切角度。
  • setTextScaleX(float scaleX) 设置文字横向放缩
  • setLetterSpacing(float letterSpacing) 设置字符间距
  • setFontFeatureSettings(String settings) 用 CSS 的 font-feature-settings 的方式来设置文字。
  • setTextAlign(Paint.Align align) 设置文字的对齐方式。一共有三个值:LEFT CETNER 和 RIGHT。默认值为 LEFT。
  • setTextLocale(Locale locale) / setTextLocales(LocaleList locales) 设置绘制所使用的 Locale,Locale.TAIWAN繁体中文
测量文字尺寸类
  • float getFontSpacing() 获取推荐的行距,即推荐的两行文字的 baseline 的距离
  • getFontMetrics(FontMetrics fontMetrics) 这种用法在需要频繁获取 FontMetrics 的时候性能会好些,能获得ascent, descent, top, bottom, leading。使用Paint.getFontMetrics()的方式进行文字居中,使⽤ (fontMetrics.ascend + fontMetrics.descend) / 2,没有getTextBounds方式的绝对居中,但是当需要居中的文字变化时不会像getTextBounds方式一样跳动。
    如何成为自定义高手(一)绘制_第4张图片
    各种线.png

    ascent : 该距离是从所绘字符的baseline之上至该字符所绘制的最高点。
    descent: 该距离是从所绘字符的baseline之下至该字符所绘制的最低点。
    top: 该距离是从所绘字符的baseline之上至可绘制区域的最高点。
    bottom: 该距离是从所绘字符的baseline之下至可绘制区域的最低点。
    leading: 为文本的线之间添加额外的空间,这是官方文档直译,debug时发现一般都为0.0,该值也是系统推荐的。
    特别注意: ascent和top都是负值,而descent和bottom:都是正值,这些值都是基于baseline为坐标0的相对值。
  • getTextBounds(String text, int start, int end, Rect bounds) 获取文字的显示范围。用这种方式做文字居中的纵向测量,使⽤ (bounds.top + bounds.bottom) / 2,会使文字非常居中,但是如果是输入的形式,到导致bounds.top和bounds.bottom值发生变化。

  • float measureText(String text) 测量文字的宽度并返回

  • getTextWidths(String text, float[] widths) 获取字符串中每个字符的宽度,并把结果填入参数 widths。

  • int breakText(String text, boolean measureForwards, float maxWidth, float[] measuredWidth) breakText() 是在给出宽度上限的前提下测量文字的宽度,返回值是截取的文字个数。参数中, text 是要测量的文字;measureForwards 表示文字的测量方向,true 表示由左往右测量;maxWidth 是给出的宽度上限;measuredWidth 是用于接受数据,而不是用于提供数据的:方法测量完成后会把截取的文字宽度(如果宽度没有超限,则为文字总宽度)赋值给 measuredWidth[0]。

  • getRunAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset) 对于一段文字,计算出某个字符处光标的 x 坐标。start end 是文字的起始和结束坐标;contextStart contextEnd 是上下文的起始和结束坐标;isRtl 是文字的方向;offset 是字数的偏移,即计算第几个字符处的光标。

  • getOffsetForAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance) 给出一个位置的像素值,计算出文字中最接近这个位置的字符偏移量(即第几个字符最接近这个坐标)。

  • 检查指定的字符串中是否是一个单独的字形 (glyph)
    自定义 View 1-3 drawText() 文字的绘制

4.Canvas 对绘制的辅助

范围裁切
  • clipRect() 裁剪矩形,记得要加上 Canvas.save() 和 Canvas.restore() 来及时恢复绘制范围
  • clipPath() 裁剪Path范围形状
几何变换

使用 Canvas 来做常见的二维变换;
使用 Matrix 来做常见和不常见的二维变换;
使用 Camera 来做三维变换。

  • Canvas.translate(float dx, float dy) 平移,参数里的 dx 和 dy 表示横向和纵向的位移。
  • Canvas.rotate(float degrees, float px, float py) 旋转,参数里的 degrees 是旋转角度,单位是度(也就是一周有 360° 的那个单位),方向是顺时针为正向; px 和 py 是轴心的位置
  • Canvas.scale(float sx, float sy, float px, float py) 放缩,参数里的 sx sy 是横向和纵向的放缩倍数; px py 是放缩的轴心
  • Canvas.skew(float sx, float sy) 错切,参数里的 sx 和 sy 是 x 方向和 y 方向的错切系数。
  • 使用 Matrix 来做变换
  1. 创建 Matrix 对象;
  2. 调用 Matrix 的pre/postTranslate/Rotate/Scale/Skew() 方法来设置几何变换;
  3. 使用 Canvas.setMatrix(matrix) 或 Canvas.concat(matrix) 来把几何变换应用到 Canvas。
  • Matrix.setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) 用点对点映射的方式设置变换
  • Camera.rotate*() 三维旋转
  • Camera.translate(float x, float y, float z) 移动
  • Camera.setLocation(x, y, z) 设置虚拟相机的位置

Canvas 的几何变换方法参照的是 View 的坐标系,而绘制方法(drawXxx())参照的是Canvas 自己的坐标系。
Canvas 的变换方法多次调用的时候,由于 Canvas 的坐标系会整体被变换,因此当平移、旋转、放缩、错切等变换多重存在的时候, Canvas 的变换参数会非常难以计算,因此可以改用倒序的理解方式
Canvas 对绘制的辅助 clipXXX() 和 Matrix

5.绘制顺序

super.onDraw() 前 or 后

根据自己的需求判断是否将自己绘制的内容放前或者后。

dispatchDraw():绘制子 View 的方法

Android 的绘制顺序:在绘制过程中,每一个 ViewGroup 会先调用自己的 onDraw() 来绘制完自己的主体之后再去绘制它的子 View。就是ViewGroup会先调用onDraw,然后调用dispatchDraw。

绘制过程简述
  • 背景
  • 主体(onDraw())
  • 子 View(dispatchDraw())
  • 滑动边缘渐变和滑动条
  • 前景
如何成为自定义高手(一)绘制_第5张图片
绘制过程
onDrawForeground()

在 onDrawForeground() 中,会依次绘制滑动边缘渐变、滑动条和前景。如果你把绘制代码写在了 super.onDrawForeground() 的下面,绘制代码会在滑动边缘渐变、滑动条和前景之后被执行,那么绘制内容将会盖住滑动边缘渐变、滑动条和前景。写在了 super.onDrawForeground() 的上面,则滑动边缘渐变、滑动条和前景将会盖住绘制内容。

draw() 总调度方法

draw() 是绘制过程的总调度方法。一个 View 的整个绘制过程都发生在 draw() 方法里。前面讲到的背景、主体、子 View 、滑动相关以及前景的绘制,它们其实都是在 draw() 方法里的。


如何成为自定义高手(一)绘制_第6张图片
整个流程
如何成为自定义高手(一)绘制_第7张图片
image

View绘制顺序Draw相关

如何成为自定义高手(一)绘制
如何成为自定义高手(二)动画
如何成为自定义高手(三)布局
如何成为自定义高手(四)触摸反馈,事件分发机制
如何成为自定义高手(五)多点触摸
如何成为自定义高手(六)滑动和拖拽
如何成为自定义高手(七)滑动冲突

你可能感兴趣的:(如何成为自定义高手(一)绘制)