diff --git a/CustomView/Advance/[01]CustomViewProcess.md b/CustomView/Advance/[01]CustomViewProcess.md index f6687bb..5166f06 100644 --- a/CustomView/Advance/[01]CustomViewProcess.md +++ b/CustomView/Advance/[01]CustomViewProcess.md @@ -16,17 +16,17 @@ ## 一.自定义View分类 **我将自定义View分为了两类(sloop个人分类法,非官方):** - + ### 1.自定义ViewGroup - + **自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件,大多继承自ViewGroup或各种Layout,包含有子View。** - + > 例如:应用底部导航条中的条目,一般都是上面图标(ImageView),下面文字(TextView),那么这两个就可以用自定义ViewGroup组合成为一个Veiw,提供两个属性分别用来设置文字和图片,使用起来会更加方便。 - + ### 2.自定义View - + **在没有现成的View,需要自己实现的时候,就使用自定义View,一般继承自View,SurfaceView或其他的View,不包含子View。** - + > 例如:制作一个支持自动加载网络图片的ImageView,制作图表等。 **PS: 自定义View在大多数情况下都有替代方案,利用图片或者组合动画来实现,但是使用后者可能会面临内存耗费过大,制作麻烦更诸多问题。** @@ -47,9 +47,9 @@ View的构造函数有四种重载分别如下: public void SloopView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {} ``` 可以看出,关于View构造函数的参数有多有少,先排除几个不常用的,留下常用的再研究。 - + **有四个参数的构造函数在API21的时候才添加上,暂不考虑。** - + 有三个参数的构造函数中第三个参数是默认的Style,这里的默认的Style是指它在当前Application或Activity所用的Theme中的默认Style,且只有在明确调用的时候才会生效,以系统中的ImageButton为例说明: ``` java public ImageButton(Context context, AttributeSet attrs) { @@ -111,21 +111,21 @@ View的构造函数有四种重载分别如下: **测量模式一共有三种, 被定义在 Android 中的 View 类的一个内部类View.MeasureSpec中:** -模式 | 二进制数值 | 描述 ------------ |:----------:| --- -UNSPECIFIED | 00 | 默认值,父控件没有给子view任何限制,子View可以设置为任意大小。 -EXACTLY | 01 | 表示父控件已经确切的指定了子View的大小。 -AT_MOST | 10 | 表示子View具体大小没有尺寸限制,但是存在上限,上限一般为父View大小。 +| 模式 | 二进制数值 | 描述 | +| ----------- | :---: | -------------------------------------- | +| UNSPECIFIED | 00 | 默认值,父控件没有给子view任何限制,子View可以设置为任意大小。 | +| EXACTLY | 01 | 表示父控件已经确切的指定了子View的大小。 | +| AT_MOST | 10 | 表示子View具体大小没有尺寸限制,但是存在上限,上限一般为父View大小。 | **在int类型的32位二进制位中,31-30这两位表示测量模式,29~0这三十位表示宽和高的实际值,实际上如下:** 以数值1080(二进制为: 1111011000)为例(其中模式和实际数值是连在一起的,为了展示我将他们分开了): -模式名称 | 模式数值 | 实际数值 -------------| --------:| --- -UNSPECIFIED | 00 | 000000000000000000001111011000 -EXACTLY | 01 | 000000000000000000001111011000 -AT_MOST | 10 | 000000000000000000001111011000 +| 模式名称 | 模式数值 | 实际数值 | +| ----------- | ---: | ------------------------------ | +| UNSPECIFIED | 00 | 000000000000000000001111011000 | +| EXACTLY | 01 | 000000000000000000001111011000 | +| AT_MOST | 10 | 000000000000000000001111011000 | **PS: 实际上关于上面的东西了解即可,在实际运用之中只需要记住有三种模式,用 MeasureSpec 的 getSize是获取数值, getMode是获取模式即可。** @@ -136,7 +136,7 @@ AT_MOST | 10 | 000000000000000000001111011000 ### 3.确定View大小(onSizeChanged) 这个函数在视图大小发生改变时调用。 - + **Q: 在测量完View并使用setMeasuredDimension函数之后View的大小基本上已经确定了,那么为什么还要再次确定View的大小呢?** **A: 这是因为View的大小不仅由View本身控制,而且受父控件的影响,所以我们在确定View大小的时候最好使用系统提供的onSizeChanged回调函数。** @@ -157,32 +157,32 @@ onSizeChanged如下: ### 4.确定子View布局位置(onLayout) **确定布局的函数是onLayout,它用于确定子View的位置,在自定义ViewGroup中会用到,他调用的是子View的layout函数。** - + 在自定义ViewGroup中,onLayout一般是循环取出子View,然后经过计算得出各个子View位置的坐标值,然后用以下函数设置子View位置。 - + ``` java child.layout(l, t, r, b); ``` 四个参数分别为: -名称 | 说明 | 对应的函数 ----- | -------------------------- | --- -l | View左侧距父View左侧的距离 | getLeft(); -t | View顶部距父View顶部的距离 | getTop(); -r | View右侧距父View左侧的距离 | getRight(); -b | View底部距父View顶部的距离 | getBottom(); +| 名称 | 说明 | 对应的函数 | +| ---- | ----------------- | ------------ | +| l | View左侧距父View左侧的距离 | getLeft(); | +| t | View顶部距父View顶部的距离 | getTop(); | +| r | View右侧距父View左侧的距离 | getRight(); | +| b | View底部距父View顶部的距离 | getBottom(); | -具体可以参考 [坐标系](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Base/%5B1%5DCoordinateSystem.md) 这篇文章。 +具体可以参考 [坐标系](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Base/%5B01%5DCoordinateSystem.md) 这篇文章。 ![](http://ww2.sinaimg.cn/large/005Xtdi2gw1f1qzqwvkkbj308c0dwgm9.jpg) PS:关于onLayout这个函数在讲解自定义ViewGroup的时候会详细讲解。 - - + + ======== ### 5.绘制内容(onDraw) - + onDraw是实际绘制的部分,也就是我们真正关心的部分,使用的是Canvas绘图。 ``` java @Override @@ -196,7 +196,7 @@ b | View底部距父View顶部的距离 | getBottom(); ### 6.对外提供操作方法和监听回调 自定义完View之后,一般会对外暴露一些接口,用于控制View的状态等,或者监听View的变化. - + 本内容会在后续文章中以实例的方式进讲解。 ************ @@ -207,20 +207,20 @@ b | View底部距父View顶部的距离 | getBottom(); > PS :实际上ViewGroup是View的一个子类。 -类别 | 继承自 | 特点 ---------- | --------------------- | ------------ -View | View SurfaceView 等 | 不含子View -ViewGroup | ViewGroup xxLayout等 | 包含子View +| 类别 | 继承自 | 特点 | +| --------- | ------------------- | ------- | +| View | View SurfaceView 等 | 不含子View | +| ViewGroup | ViewGroup xxLayout等 | 包含子View | ### 自定义View流程: -步骤 | 关键字 | 作用 ----- | ------------- | ------------- - 1 | 构造函数 | View初始化 - 2 | onMeasure | 测量View大小 - 3 | onSizeChanged | 确定View大小 - 4 | onLayout | 确定子View布局(自定义View包含子View时有用) - 5 | onDraw | 实际绘制内容 - 6 | 提供接口 | 控制View或监听View某些状态。 +| 步骤 | 关键字 | 作用 | +| ---- | ------------- | ---------------------------- | +| 1 | 构造函数 | View初始化 | +| 2 | onMeasure | 测量View大小 | +| 3 | onSizeChanged | 确定View大小 | +| 4 | onLayout | 确定子View布局(自定义View包含子View时有用) | +| 5 | onDraw | 实际绘制内容 | +| 6 | 提供接口 | 控制View或监听View某些状态。 | diff --git a/CustomView/Advance/[02]Canvas_BasicGraphics.md b/CustomView/Advance/[02]Canvas_BasicGraphics.md index b0b2eef..28820e8 100644 --- a/CustomView/Advance/[02]Canvas_BasicGraphics.md +++ b/CustomView/Advance/[02]Canvas_BasicGraphics.md @@ -3,7 +3,7 @@ ### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop) ### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView/README.md) -在上一篇[自定义View分类与流程](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B1%5DCustomViewProcess.md)中我们了解自定义View相关的基本知识,不过,这些东西依旧还是理论,并不能**拿来(zhuang)用(B)**, 这一次我们就了解一些**能(zhaung)用(B)**的东西。 +在上一篇[自定义View分类与流程](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B01%5DCustomViewProcess.md)中我们了解自定义View相关的基本知识,不过,这些东西依旧还是理论,并不能**拿来(zhuang)用(B)**, 这一次我们就了解一些**能(zhaung)用(B)**的东西。 在本篇文章中,我们先了解Canvas的基本用法,最后用一个小示例来结束本次教程。 @@ -50,7 +50,7 @@ Canvas我们可以称之为画布,能够在上面绘制各种东西,是安 -> 关于颜色的更多资料请参考[基础篇_颜色](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView%2FBase%2F%5B3%5DColor.md) +> 关于颜色的更多资料请参考[基础篇_颜色](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView%2FBase%2F%5B03%5DColor.md) ****** @@ -90,7 +90,7 @@ Canvas我们可以称之为画布,能够在上面绘制各种东西,是安 ``` 关于坐标原点默认在左上角,水平向右为x轴增大方向,竖直向下为y轴增大方向。 -> 更多参考这里 [基础篇_坐标系](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView%2FBase%2F%5B1%5DCoordinateSystem.md) +> 更多参考这里 [基础篇_坐标系](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView%2FBase%2F%5B01%5DCoordinateSystem.md) @@ -274,7 +274,7 @@ useCenter // 是否使用中心 -可以发现使用了中心点之后绘制出来类似于一个扇形,而不使用中心点则是圆弧起始点和结束点之间的连线加上圆弧围成的图形。这样中心点这个参数的作用就很明显了,不必多说想必大家试一下就明白了。 另外可以关于角度可以参考一下这篇文章: [角度与弧度](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView%2FBase%2F%5B2%5DAngleAndRadian.md) +可以发现使用了中心点之后绘制出来类似于一个扇形,而不使用中心点则是圆弧起始点和结束点之间的连线加上圆弧围成的图形。这样中心点这个参数的作用就很明显了,不必多说想必大家试一下就明白了。 另外可以关于角度可以参考一下这篇文章: [角度与弧度](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView%2FBase%2F%5B02%5DAngleAndRadian.md) 相比于使用椭圆,我们还是使用正圆比较多的,使用正圆展示一下效果: diff --git a/CustomView/Advance/[03]Canvas_Convert.md b/CustomView/Advance/[03]Canvas_Convert.md index b462e3e..13f253b 100644 --- a/CustomView/Advance/[03]Canvas_Convert.md +++ b/CustomView/Advance/[03]Canvas_Convert.md @@ -3,24 +3,24 @@ ### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop) ### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView/README.md) -上一篇[Canvas之绘制基本形状](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B2%5DCanvas_BasicGraphics.md)中我们了解了如何使用Canvas绘制基本图形,本次了解一些基本的画布操作。 +上一篇[Canvas之绘制基本形状](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B02%5DCanvas_BasicGraphics.md)中我们了解了如何使用Canvas绘制基本图形,本次了解一些基本的画布操作。 本来想把画布操作放到后面部分的,但是发现很多图形绘制都离不开画布操作,于是先讲解一下画布的基本操作方法。 ## 一.Canvas的常用操作速查表 -操作类型 | 相关API | 备注 ---- | --- | --- -绘制颜色 | drawColor, drawRGB, drawARGB | 使用单一颜色填充整个画布 -绘制基本形状 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧 -绘制图片 | drawBitmap, drawPicture | 绘制位图和图片 -绘制文本 | drawText, drawPosText, drawTextOnPath | 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字 -绘制路径 | drawPath | 绘制路径,绘制贝塞尔曲线时也需要用到该函数 -顶点操作 | drawVertices, drawBitmapMesh | 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用 -画布剪裁 | clipPath, clipRect | 设置画布的显示区域 -画布快照 | save, restore, saveLayerXxx, restoreToCount, getSaveCount | 依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数 -画布变换 | translate, scale, rotate, skew | 依次为 位移、缩放、 旋转、错切 -Matrix(矩阵) | getMatrix, setMatrix, concat | 实际上画布的位移,缩放等操作的都是图像矩阵Matrix, 只不过Matrix比较难以理解和使用,故封装了一些常用的方法。 +| 操作类型 | 相关API | 备注 | +| ---------- | ---------------------------------------- | ---------------------------------------- | +| 绘制颜色 | drawColor, drawRGB, drawARGB | 使用单一颜色填充整个画布 | +| 绘制基本形状 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧 | +| 绘制图片 | drawBitmap, drawPicture | 绘制位图和图片 | +| 绘制文本 | drawText, drawPosText, drawTextOnPath | 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字 | +| 绘制路径 | drawPath | 绘制路径,绘制贝塞尔曲线时也需要用到该函数 | +| 顶点操作 | drawVertices, drawBitmapMesh | 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用 | +| 画布剪裁 | clipPath, clipRect | 设置画布的显示区域 | +| 画布快照 | save, restore, saveLayerXxx, restoreToCount, getSaveCount | 依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数 | +| 画布变换 | translate, scale, rotate, skew | 依次为 位移、缩放、 旋转、错切 | +| Matrix(矩阵) | getMatrix, setMatrix, concat | 实际上画布的位移,缩放等操作的都是图像矩阵Matrix, 只不过Matrix比较难以理解和使用,故封装了一些常用的方法。 | ****** ## 二.Canvas基本操作 @@ -77,15 +77,15 @@ Matrix(矩阵) | getMatrix, setMatrix, concat | 实际上画布的位移,缩 缩放比例(sx,sy)取值范围详解: -取值范围(n)| 说明 ---------- | ------ -[-∞, -1) | 先根据缩放中心放大n倍,再根据中心轴进行翻转 --1 | 根据缩放中心轴进行翻转 -(-1, 0) | 先根据缩放中心缩小到n,再根据中心轴进行翻转 -0 | 不会显示,若sx为0,则宽度为0,不会显示,sy同理 -(0, 1) | 根据缩放中心缩小到n -1 | 没有变化 -(1, +∞) | 根据缩放中心放大n倍 +| 取值范围(n) | 说明 | +| -------- | -------------------------- | +| [-∞, -1) | 先根据缩放中心放大n倍,再根据中心轴进行翻转 | +| -1 | 根据缩放中心轴进行翻转 | +| (-1, 0) | 先根据缩放中心缩小到n,再根据中心轴进行翻转 | +| 0 | 不会显示,若sx为0,则宽度为0,不会显示,sy同理 | +| (0, 1) | 根据缩放中心缩小到n | +| 1 | 没有变化 | +| (1, +∞) | 根据缩放中心放大n倍 | 如果在缩放时稍微注意一下就会发现缩放的中心默认为坐标原点,而缩放中心轴就是坐标轴,如下: @@ -330,13 +330,13 @@ A:画布的操作是不可逆的,而且很多画布操作会影响后续的 与之相关的API: -相关API | 简介 ---- | --- -save | 把当前的画布的状态进行保存,然后放入特定的栈中 -saveLayerXxx | 新建一个图层,并放入特定的栈中 -restore | 把栈中最顶层的画布状态取出来,并按照这个状态恢复当前的画布 -restoreToCount| 弹出指定位置及其以上所有的状态,并按照指定位置的状态进行恢复 -getSaveCount | 获取栈中内容的数量(即保存次数) +| 相关API | 简介 | +| -------------- | ------------------------------ | +| save | 把当前的画布的状态进行保存,然后放入特定的栈中 | +| saveLayerXxx | 新建一个图层,并放入特定的栈中 | +| restore | 把栈中最顶层的画布状态取出来,并按照这个状态恢复当前的画布 | +| restoreToCount | 弹出指定位置及其以上所有的状态,并按照指定位置的状态进行恢复 | +| getSaveCount | 获取栈中内容的数量(即保存次数) | 下面对其中的一些概念和方法进行分析: @@ -359,14 +359,14 @@ A:实际上我们看到的画布是由多个图层构成的,如下图(图片 ##### SaveFlags -数据类型 | 名称 | 简介 ---- | --- | --- -int | ALL_SAVE_FLAG | 默认,保存全部状态 -int | CLIP_SAVE_FLAG | 保存剪辑区 -int | CLIP_TO_LAYER_SAVE_FLAG | 剪裁区作为图层保存 -int | FULL_COLOR_LAYER_SAVE_FLAG | 保存图层的全部色彩通道 -int | HAS_ALPHA_LAYER_SAVE_FLAG | 保存图层的alpha(不透明度)通道 -int | MATRIX_SAVE_FLAG | 保存Matrix信息(translate, rotate, scale, skew) +| 数据类型 | 名称 | 简介 | +| ---- | -------------------------- | ---------------------------------------- | +| int | ALL_SAVE_FLAG | 默认,保存全部状态 | +| int | CLIP_SAVE_FLAG | 保存剪辑区 | +| int | CLIP_TO_LAYER_SAVE_FLAG | 剪裁区作为图层保存 | +| int | FULL_COLOR_LAYER_SAVE_FLAG | 保存图层的全部色彩通道 | +| int | HAS_ALPHA_LAYER_SAVE_FLAG | 保存图层的alpha(不透明度)通道 | +| int | MATRIX_SAVE_FLAG | 保存Matrix信息(translate, rotate, scale, skew) | ##### save save 有两种方法: diff --git a/CustomView/Advance/[04]Canvas_PictureText.md b/CustomView/Advance/[04]Canvas_PictureText.md index 8dc2529..9644f4f 100644 --- a/CustomView/Advance/[04]Canvas_PictureText.md +++ b/CustomView/Advance/[04]Canvas_PictureText.md @@ -3,22 +3,22 @@ ### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop) ### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView/README.md) -在上一篇文章[Canvas之画布操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B3%5DCanvas_Convert.md)中我们了解了画布的一些基本操作方法,本次了解一些绘制图片文字相关的内容。如果你对前几篇文章讲述的内容熟练掌握的话,那么恭喜你,本篇结束之后,大部分的自定义View已经难不倒你了,当然了,这并不是终点,接下来还会有更加炫酷的技能。 +在上一篇文章[Canvas之画布操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B03%5DCanvas_Convert.md)中我们了解了画布的一些基本操作方法,本次了解一些绘制图片文字相关的内容。如果你对前几篇文章讲述的内容熟练掌握的话,那么恭喜你,本篇结束之后,大部分的自定义View已经难不倒你了,当然了,这并不是终点,接下来还会有更加炫酷的技能。 ## 一.Canvas的常用操作速查表 -操作类型 | 相关API | 备注 ----------|---------|----------- -绘制颜色 | drawColor, drawRGB, drawARGB | 使用单一颜色填充整个画布 -绘制基本形状 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧 -绘制图片 | drawBitmap, drawPicture | 绘制位图和图片 -绘制文本 | drawText, drawPosText, drawTextOnPath | 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字 -绘制路径 | drawPath | 绘制路径,绘制贝塞尔曲线时也需要用到该函数 -顶点操作 | drawVertices, drawBitmapMesh | 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用 -画布剪裁 | clipPath, clipRect | 设置画布的显示区域 -画布快照 | save, restore, saveLayerXxx, restoreToCount, getSaveCount | 依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数 -画布变换 | translate, scale, rotate, skew | 依次为 位移、缩放、 旋转、错切 -Matrix(矩阵) | getMatrix, setMatrix, concat | 实际上画布的位移,缩放等操作的都是图像矩阵Matrix, 只不过Matrix比较难以理解和使用,故封装了一些常用的方法。 +| 操作类型 | 相关API | 备注 | +| ---------- | ---------------------------------------- | ---------------------------------------- | +| 绘制颜色 | drawColor, drawRGB, drawARGB | 使用单一颜色填充整个画布 | +| 绘制基本形状 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧 | +| 绘制图片 | drawBitmap, drawPicture | 绘制位图和图片 | +| 绘制文本 | drawText, drawPosText, drawTextOnPath | 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字 | +| 绘制路径 | drawPath | 绘制路径,绘制贝塞尔曲线时也需要用到该函数 | +| 顶点操作 | drawVertices, drawBitmapMesh | 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用 | +| 画布剪裁 | clipPath, clipRect | 设置画布的显示区域 | +| 画布快照 | save, restore, saveLayerXxx, restoreToCount, getSaveCount | 依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数 | +| 画布变换 | translate, scale, rotate, skew | 依次为 位移、缩放、 旋转、错切 | +| Matrix(矩阵) | getMatrix, setMatrix, concat | 实际上画布的位移,缩放等操作的都是图像矩阵Matrix, 只不过Matrix比较难以理解和使用,故封装了一些常用的方法。 | ****** # 二.Canvas基本操作详解 @@ -68,15 +68,15 @@ A Picture records drawing calls (via the canvas returned by beginRecording) and 了解了Picture的概念之后,我们再了解一下Picture的相关方法。 -相关方法 | 简介 -------------------------------------------------------------|-------------------- -public int getWidth () | 获取宽度 -public int getHeight () | 获取高度 -public Canvas beginRecording (int width, int height) | 开始录制 (返回一个Canvas,在Canvas中所有的绘制都会存储在Picture中) -public void endRecording () | 结束录制 -public void draw (Canvas canvas) | 将Picture中内容绘制到Canvas中 -public static Picture createFromStream (InputStream stream) | (已废弃)通过输入流创建一个Picture -public void writeToStream (OutputStream stream) | (已废弃)将Picture中内容写出到输出流中 +| 相关方法 | 简介 | +| ---------------------------------------- | ---------------------------------------- | +| public int getWidth () | 获取宽度 | +| public int getHeight () | 获取高度 | +| public Canvas beginRecording (int width, int height) | 开始录制 (返回一个Canvas,在Canvas中所有的绘制都会存储在Picture中) | +| public void endRecording () | 结束录制 | +| public void draw (Canvas canvas) | 将Picture中内容绘制到Canvas中 | +| public static Picture createFromStream (InputStream stream) | (已废弃)通过输入流创建一个Picture | +| public void writeToStream (OutputStream stream) | (已废弃)将Picture中内容写出到输出流中 | 上面表格中基本上已经列出了Picture的所有方法,其中getWidth和getHeight没什么好说的,最后两个已经废弃也自然就不用关注了,排除了这些方法之后,只剩三个方法了,接下来我们就比较详细的了解一下: @@ -127,19 +127,19 @@ public void writeToStream (OutputStream stream) | (已废弃)将Pict Picture虽然方法就那么几个,但是具体使用起来还是分很多情况的,由于录制的内容不会直接显示,就像存储的视频不点击播放不会自动播放一样,同样,想要将Picture中的内容显示出来就需要手动调用播放(绘制),将Picture中的内容绘制出来可以有以下几种方法: -序号 | 简介 ------|----------- - 1 | 使用Picture提供的draw方法绘制。 - 2 | 使用Canvas提供的drawPicture方法绘制。 - 3 | 将Picture包装成为PictureDrawable,使用PictureDrawable的draw方法绘制。 +| 序号 | 简介 | +| ---- | ---------------------------------------- | +| 1 | 使用Picture提供的draw方法绘制。 | +| 2 | 使用Canvas提供的drawPicture方法绘制。 | +| 3 | 将Picture包装成为PictureDrawable,使用PictureDrawable的draw方法绘制。 | 以上几种方法主要区别: -主要区别 | 分类 | 简介 --------------------|-----------------------------------|------------------ -是否对Canvas有影响 | 1有影响
2,3不影响 | 此处指绘制完成后是否会影响Canvas的状态(Matrix clip等) -可操作性强弱 | 1可操作性较弱
2,3可操作性较强 | 此处的可操作性可以简单理解为对绘制结果可控程度。 +| 主要区别 | 分类 | 简介 | +| ------------ | --------------------- | ------------------------------------ | +| 是否对Canvas有影响 | 1有影响
2,3不影响 | 此处指绘制完成后是否会影响Canvas的状态(Matrix clip等) | +| 可操作性强弱 | 1可操作性较弱
2,3可操作性较强 | 此处的可操作性可以简单理解为对绘制结果可控程度。 | 几种方法简介和主要区别基本就这么多了,接下来对于各种使用方法一一详细介绍: @@ -170,9 +170,9 @@ public void drawPicture (Picture picture, RectF dst) ``` java canvas.drawPicture(mPicture,new RectF(0,0,mPicture.getWidth(),200)); ``` - + - + **PS:对照上一张图片,可以比较明显的看出,绘制的内容根据选区进行了缩放。 ** **3.将Picture包装成为PictureDrawable,使用PictureDrawable的draw方法绘制。** @@ -197,15 +197,15 @@ public void drawPicture (Picture picture, RectF dst) > 其实一开始知道要讲Bitmap我是拒绝的,为什么呢?因为Bitmap就是很多问题的根源啊有木有,Bitmap可能导致内存不足,内存泄露,ListView中的复用混乱等诸多问题。想完美的掌控Bitmap还真不是一件容易的事情。限于篇幅**本文对于Bitmap不会过多的展开,只讲解一些常用的功能**,关于Bitmap详细内容,以后开专题讲解QAQ。 既然要绘制Bitmap,就要先获取一个Bitmap,那么如何获取呢? - + **获取Bitmap方式:** - - 序号 | 获取方式 | 备注 - -----|---------------------------|----------------------------------------- - 1 | 通过Bitmap创建 | 复制一个已有的Bitmap(_新Bitmap状态和原有的一致_) 或者 创建一个空白的Bitmap(_内容可改变_) - 2 | 通过BitmapDrawable获取 | 从资源文件 内存卡 网络等地方获取一张图片并转换为内容不可变的Bitmap - 3 | 通过BitmapFactory获取 | 从资源文件 内存卡 网络等地方获取一张图片并转换为内容不可变的Bitmap - + +| 序号 | 获取方式 | 备注 | +| ---- | ------------------ | ---------------------------------------- | +| 1 | 通过Bitmap创建 | 复制一个已有的Bitmap(_新Bitmap状态和原有的一致_) 或者 创建一个空白的Bitmap(_内容可改变_) | +| 2 | 通过BitmapDrawable获取 | 从资源文件 内存卡 网络等地方获取一张图片并转换为内容不可变的Bitmap | +| 3 | 通过BitmapFactory获取 | 从资源文件 内存卡 网络等地方获取一张图片并转换为内容不可变的Bitmap | + **通常来说,我们绘制Bitmap都是读取已有的图片转换为Bitmap绘制到Canvas上。**
很明显,第1种方式不能满足我们的要求,暂时排除。
第2种方式虽然也可满足我们的要求,但是我不推荐使用这种方式,至于为什么在后续详细讲解Drawable的时候会说明,暂时排除。
@@ -282,10 +282,10 @@ PS:图片左上角位置默认为坐标原点。 第三种方法比较有意思,上面多了两个矩形区域(src,dst),这两个矩形选区是干什么用的? -名称 | 作用 ---------------------------|--------------------- -Rect src | 指定绘制图片的区域 -Rect dst 或RectF dst | 指定图片在屏幕上显示(绘制)的区域 +| 名称 | 作用 | +| ------------------- | ----------------- | +| Rect src | 指定绘制图片的区域 | +| Rect dst 或RectF dst | 指定图片在屏幕上显示(绘制)的区域 | 示例: ``` java @@ -372,14 +372,14 @@ Rect dst 或RectF dst | 指定图片在屏幕上显示(绘制)的区域 **Paint文本相关常用方法表** -标题 | 相关方法 | 备注 ------|---------------------------|---------------------- -色彩 | setColor setARGB setAlpha | 设置颜色,透明度 -大小 | setTextSize | 设置文本字体大小 -字体 | setTypeface | 设置或清除字体样式 -样式 | setStyle | 填充(FILL),描边(STROKE),填充加描边(FILL_AND_STROKE) -对齐 | setTextAlign | 左对齐(LEFT),居中对齐(CENTER),右对齐(RIGHT) -测量 | measureText | 测量文本大小(注意,请在设置完文本各项参数后调用) +| 标题 | 相关方法 | 备注 | +| ---- | ------------------------- | ---------------------------------------- | +| 色彩 | setColor setARGB setAlpha | 设置颜色,透明度 | +| 大小 | setTextSize | 设置文本字体大小 | +| 字体 | setTypeface | 设置或清除字体样式 | +| 样式 | setStyle | 填充(FILL),描边(STROKE),填充加描边(FILL_AND_STROKE) | +| 对齐 | setTextAlign | 左对齐(LEFT),居中对齐(CENTER),右对齐(RIGHT) | +| 测量 | measureText | 测量文本大小(注意,请在设置完文本各项参数后调用) | 为了绘制文本,我们先创建一个文本画笔: ``` java @@ -411,9 +411,9 @@ Rect dst 或RectF dst | 指定图片在屏幕上显示(绘制)的区域 以上一个例子使用的字符串为例,它的下标是这样的(wait,我为啥要说这个,算了,不管了,就这样吧(๑•́ ₃ •̀๑)): -字符 | A | B | C | D | E | F | G | H | I | J | K - ---|---|---|---|---|---|---|---|---|---|---|--- -下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 +| 字符 | A | B | C | D | E | F | G | H | I | J | K | +| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | +| 下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 假设我我们指定star为1,end为3,那么最终截取的字符串就是"BC"。 @@ -465,11 +465,11 @@ Rect dst 或RectF dst | 指定图片在屏幕上显示(绘制)的区域 不过嘛,虽然虽然这个方法也比较容易理解,但是关于这个方法我个人是不推荐使用的,因为坑比较多,主要有一下几点: -序号 | 反对理由 ------|---------------------- - 1 | 必须指定所有字符位置,否则直接crash掉,反人类设计 - 2 | 性能不佳,在大量使用的时候可能导致卡顿 - 3 | 不支持emoji等特殊字符,不支持字形组合与分解 +| 序号 | 反对理由 | +| ---- | --------------------------- | +| 1 | 必须指定所有字符位置,否则直接crash掉,反人类设计 | +| 2 | 性能不佳,在大量使用的时候可能导致卡顿 | +| 3 | 不支持emoji等特殊字符,不支持字形组合与分解 | 关于第二类的第二种方法: diff --git a/CustomView/Advance/[05]Path_Basic.md b/CustomView/Advance/[05]Path_Basic.md index d3641a4..225ef09 100644 --- a/CustomView/Advance/[05]Path_Basic.md +++ b/CustomView/Advance/[05]Path_Basic.md @@ -4,32 +4,32 @@ ### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView/README.md) -在上一篇[Canvas之图片文字](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B4%5DCanvas_PictureText.md)中我们了解了如何使用Canvas中绘制图片文字,结合前几篇文章,Canvas的基本操作已经差不多完结了,然而Canvas不仅仅具有这些基本的操作,还可以更加炫酷,本次会了解到path(路径)这个Canvas中的神器,有了这个神器,就能创造出更多**炫(zhuang)酷(B)**的东东了。 +在上一篇[Canvas之图片文字](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B04%5DCanvas_PictureText.md)中我们了解了如何使用Canvas中绘制图片文字,结合前几篇文章,Canvas的基本操作已经差不多完结了,然而Canvas不仅仅具有这些基本的操作,还可以更加炫酷,本次会了解到path(路径)这个Canvas中的神器,有了这个神器,就能创造出更多**炫(zhuang)酷(B)**的东东了。 ****** # 一.Path常用方法表 > 为了兼容性(_偷懒_) 本表格中去除了部分API21(即安卓版本5.0)以上才添加的方法。 -作用 | 相关方法 | 备注 -----------------|-----------------|------------------------------------------ -移动起点 | moveTo | 移动下一次操作的起点位置 -设置终点 | setLastPoint | 重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同 -连接直线 | lineTo | 添加上一个点到当前点之间的直线到Path -闭合路径 | close | 连接第一个点连接到最后一个点,形成一个闭合区域 -添加内容 | addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo | 添加(矩形, 圆角矩形, 椭圆, 圆, 路径, 圆弧) 到当前Path (注意addArc和arcTo的区别) -是否为空 | isEmpty | 判断Path是否为空 -是否为矩形 | isRect | 判断path是否是一个矩形 -替换路径 | set | 用新的路径替换到当前路径所有内容 -偏移路径 | offset | 对当前路径之前的操作进行偏移(不会影响之后的操作) -贝塞尔曲线 | quadTo, cubicTo | 分别为二次和三次贝塞尔曲线的方法 -rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)** -填充模式 | setFillType, getFillType, isInverseFillType, toggleInverseFillType | 设置,获取,判断和切换填充模式 -提示方法 | incReserve | 提示Path还有多少个点等待加入**(这个方法貌似会让Path优化存储结构)** -布尔操作(API19) | op | 对两个Path进行布尔运算(即取交集、并集等操作) -计算边界 | computeBounds | 计算Path的边界 -重置路径 | reset, rewind | 清除Path中的内容
**reset不保留内部数据结构,但会保留FillType.**
**rewind会保留内部的数据结构,但不保留FillType** -矩阵操作 | transform | 矩阵变换 +| 作用 | 相关方法 | 备注 | +| ----------- | ---------------------------------------- | ---------------------------------------- | +| 移动起点 | moveTo | 移动下一次操作的起点位置 | +| 设置终点 | setLastPoint | 重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同 | +| 连接直线 | lineTo | 添加上一个点到当前点之间的直线到Path | +| 闭合路径 | close | 连接第一个点连接到最后一个点,形成一个闭合区域 | +| 添加内容 | addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo | 添加(矩形, 圆角矩形, 椭圆, 圆, 路径, 圆弧) 到当前Path (注意addArc和arcTo的区别) | +| 是否为空 | isEmpty | 判断Path是否为空 | +| 是否为矩形 | isRect | 判断path是否是一个矩形 | +| 替换路径 | set | 用新的路径替换到当前路径所有内容 | +| 偏移路径 | offset | 对当前路径之前的操作进行偏移(不会影响之后的操作) | +| 贝塞尔曲线 | quadTo, cubicTo | 分别为二次和三次贝塞尔曲线的方法 | +| rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)** | +| 填充模式 | setFillType, getFillType, isInverseFillType, toggleInverseFillType | 设置,获取,判断和切换填充模式 | +| 提示方法 | incReserve | 提示Path还有多少个点等待加入**(这个方法貌似会让Path优化存储结构)** | +| 布尔操作(API19) | op | 对两个Path进行布尔运算(即取交集、并集等操作) | +| 计算边界 | computeBounds | 计算Path的边界 | +| 重置路径 | reset, rewind | 清除Path中的内容
**reset不保留内部数据结构,但会保留FillType.**
**rewind会保留内部的数据结构,但不保留FillType** | +| 矩阵操作 | transform | 矩阵变换 | # 二.Path详解 @@ -59,12 +59,12 @@ _The Path class encapsulates compound (multiple contour) geometric paths consist 另外路径有开放和封闭的区别。 - -图像 | 名称 | 备注 - --- | --- | --- - ![](http://ww4.sinaimg.cn/thumbnail/005Xtdi2jw1f0zx9g9gggj30f00aiwek.jpg) | 封闭路径 | 首尾相接形成了一个封闭区域 - ![](http://ww1.sinaimg.cn/thumbnail/005Xtdi2jw1f0zxg8ilpxj30f00aimx8.jpg) | 开放路径 | 没有首位相接形成封闭区域 - + +| 图像 | 名称 | 备注 | +| ---------------------------------------- | ---- | ------------- | +| ![](http://ww4.sinaimg.cn/thumbnail/005Xtdi2jw1f0zx9g9gggj30f00aiwek.jpg) | 封闭路径 | 首尾相接形成了一个封闭区域 | +| ![](http://ww1.sinaimg.cn/thumbnail/005Xtdi2jw1f0zxg8ilpxj30f00aimx8.jpg) | 开放路径 | 没有首位相接形成封闭区域 | + > 这个是我随便画的,仅为展示一下区别,请无视我灵魂画师一般的绘图水准。 **与Path相关的还有一些比较神奇的概念,不过暂且不说,等接下来需要用到的时候再详细说明。** @@ -76,18 +76,18 @@ _The Path class encapsulates compound (multiple contour) geometric paths consist ![](http://ww3.sinaimg.cn/large/005Xtdi2jw1f19mncfcirj305i02j744.jpg) ### 第1组: moveTo、 setLastPoint、 lineTo 和 close - + 由于Path的有些知识点无法单独来讲,所以本次采取了一次讲一组方法。 - + 按照惯例,先创建画笔: - + ``` java Paint mPaint = new Paint(); // 创建画笔 mPaint.setColor(Color.BLACK); // 画笔颜色 - 黑色 mPaint.setStyle(Paint.Style.STROKE); // 填充模式 - 描边 mPaint.setStrokeWidth(10); // 边框宽度 - 10 ``` - + #### lineTo: 方法预览: ``` @@ -95,9 +95,9 @@ public void lineTo (float x, float y) ``` 首先讲解的的LineTo,为啥先讲解这个呢? - + 是因为moveTo、 setLastPoint、 close都无法直接看到效果,借助有具现化效果的lineTo才能让这些方法现出原形。 - + lineTo很简单,只有一个方法,作用也很容易理解,line嘛,顾名思义就是一条线。 @@ -143,10 +143,10 @@ lineTo很简单,只有一个方法,作用也很容易理解,line嘛,顾 这两个方法虽然在作用上有相似之处,但实际上却是完全不同的两个东东,具体参照下表: -方法名 | 简介 | 是否影响之前的操作 | 是否影响之后操作 ---- | --- | --- | --- -moveTo | 移动下一次操作的起点位置 | 否 | 是 -setLastPoint | 设置之前操作的最后一个点位置 | 是 | 是 +| 方法名 | 简介 | 是否影响之前的操作 | 是否影响之后操作 | +| ------------ | -------------- | --------- | -------- | +| moveTo | 移动下一次操作的起点位置 | 否 | 是 | +| setLastPoint | 设置之前操作的最后一个点位置 | 是 | 是 | 废话不多说,直接上代码: ``` java @@ -243,19 +243,19 @@ close方法用于连接当前最后一个点和最初的一个点(如果两个 Direction的意思是 方向,趋势。 点进去看一下会发现Direction是一个枚举(Enum)类型,里面只有两个枚举常量,如下: -类型 | 解释 | 翻译 ------|-------------------|------- -CW | clockwise | 顺时针 -CCW | counter-clockwise | 逆时针 +| 类型 | 解释 | 翻译 | +| ---- | ----------------- | ---- | +| CW | clockwise | 顺时针 | +| CCW | counter-clockwise | 逆时针 | > **瞬间懵逼,我只是想添加一个基本的形状啊,搞什么顺时针和逆时针, (╯‵□′)╯︵┻━┻** **稍安勿躁,┬─┬ ノ( ' - 'ノ) {摆好摆好) 既然存在肯定是有用的,先偷偷剧透一下这个顺时针和逆时针的作用。** -序号 | 作用 ------|--------------------------------------------------- - 1 | 在添加图形时确定闭合顺序(各个点的记录顺序) - 2 | 对图形的渲染结果有影响(是判断图形渲染的重要条件) +| 序号 | 作用 | +| ---- | ------------------------- | +| 1 | 在添加图形时确定闭合顺序(各个点的记录顺序) | +| 2 | 对图形的渲染结果有影响(是判断图形渲染的重要条件) | 这个先剧透这么多,至于对闭合顺序有啥影响,自相交图形的渲染等问题等请慢慢看下去 @@ -275,7 +275,7 @@ CCW | counter-clockwise | 逆时针 **将上面代码的CW改为CCW再运行一次。接下来就是见证奇迹的时刻,两次运行结果一模一样,有木有很神奇!** > **(╯°Д°)╯︵ ┻━┻(再TM掀一次) -坑人也不带这样的啊,一毛一样要它干嘛。** +> 坑人也不带这样的啊,一毛一样要它干嘛。** **其实啊,这个东东是自带隐身技能的,想要让它现出原形,就要用到咱们刚刚学到的setLastPoint(重置当前最后一个点的位置)。** @@ -384,10 +384,10 @@ CCW | counter-clockwise | 逆时针 从名字就可以看出,这两个方法都是与圆弧相关的,作用都是添加一个圆弧到path中,但既然存在两个方法,两者之间肯定是有区别的: -名称 | 作用 | 区别 - --- | --- | --- - addArc | 添加一个圆弧到path | 直接添加一个圆弧到path中 - arcTo | 添加一个圆弧到path | 添加一个圆弧到path,如果圆弧的起点和上次最后一个坐标点不相同,就连接两个点 +| 名称 | 作用 | 区别 | +| ------ | ----------- | --------------------------------------- | +| addArc | 添加一个圆弧到path | 直接添加一个圆弧到path中 | +| arcTo | 添加一个圆弧到path | 添加一个圆弧到path,如果圆弧的起点和上次最后一个坐标点不相同,就连接两个点 | 可以看到addArc有1个方法(_实际上是两个的,但另一个重载方法是API21添加的_), 而arcTo有2个方法,其中一个最后多了一个布尔类型的变量forceMoveTo。 @@ -395,10 +395,10 @@ CCW | counter-clockwise | 逆时针 这个变量意思为“是否强制使用moveTo”,也就是说,是否使用moveTo将变量移动到圆弧的起点位移,也就意味着: -forceMoveTo | 含义 | 等价方法 - --- | --- | --- - true | 将最后一个点移动到圆弧起点,即不连接最后一个点与圆弧起点 | public void addArc (RectF oval, float startAngle, float sweepAngle) - false | 不移动,而是连接最后一个点与圆弧起点 | public void arcTo (RectF oval, float startAngle, float sweepAngle) +| forceMoveTo | 含义 | 等价方法 | +| ----------- | ---------------------------- | ---------------------------------------- | +| true | 将最后一个点移动到圆弧起点,即不连接最后一个点与圆弧起点 | public void addArc (RectF oval, float startAngle, float sweepAngle) | +| false | 不移动,而是连接最后一个点与圆弧起点 | public void arcTo (RectF oval, float startAngle, float sweepAngle) | **示例(addArc):** ``` java @@ -526,10 +526,10 @@ log 输出结果: 其实第二个方法中最后的参数das是存储平移后的path的。 -dst状态 | 效果 - --------------|--------------------------------- - dst不为空 | 将当前path平移后的状态存入dst中,不会影响当前path - dat为空(null) | 平移将作用于当前path,相当于第一种方法 +| dst状态 | 效果 | +| ----------- | ------------------------------ | +| dst不为空 | 将当前path平移后的状态存入dst中,不会影响当前path | +| dat为空(null) | 平移将作用于当前path,相当于第一种方法 | 示例: ``` java diff --git a/CustomView/Advance/[06]Path_Bezier.md b/CustomView/Advance/[06]Path_Bezier.md index 26f38ea..4384d9c 100644 --- a/CustomView/Advance/[06]Path_Bezier.md +++ b/CustomView/Advance/[06]Path_Bezier.md @@ -3,33 +3,32 @@ ### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop) ### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView/README.md) -在上一篇文章[Path之基本图形](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_BasicGraphics.md)中我们了解了Path的基本使用方法,本次了解Path中非常非常非常重要的内容-贝塞尔曲线。 - +在上一篇文章[Path之基本图形](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B05%5DPath_BasicGraphics.md)中我们了解了Path的基本使用方法,本次了解Path中非常非常非常重要的内容-贝塞尔曲线。 ****** ## 一.Path常用方法表 > 为了兼容性(_偷懒_) 本表格中去除了在API21(即安卓版本5.0)以上才添加的方法。忍不住吐槽一下,为啥看起来有些顺手就能写的重载方法要等到API21才添加上啊。宝宝此刻内心也是崩溃的。 -作用 | 相关方法 | 备注 -----------------|-----------------|------------------------------------------ -移动起点 | moveTo | 移动下一次操作的起点位置 -设置终点 | setLastPoint | 重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同 -连接直线 | lineTo | 添加上一个点到当前点之间的直线到Path -闭合路径 | close | 连接第一个点连接到最后一个点,形成一个闭合区域 -添加内容 | addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo | 添加(矩形, 圆角矩形, 椭圆, 圆, 路径, 圆弧) 到当前Path (注意addArc和arcTo的区别) -是否为空 | isEmpty | 判断Path是否为空 -是否为矩形 | isRect | 判断path是否是一个矩形 -替换路径 | set | 用新的路径替换到当前路径所有内容 -偏移路径 | offset | 对当前路径之前的操作进行偏移(不会影响之后的操作) -贝塞尔曲线 | quadTo, cubicTo | 分别为二次和三次贝塞尔曲线的方法 -rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)** -填充模式 | setFillType, getFillType, isInverseFillType, toggleInverseFillType | 设置,获取,判断和切换填充模式 -提示方法 | incReserve | 提示Path还有多少个点等待加入**(这个方法貌似会让Path优化存储结构)** -布尔操作(API19) | op | 对两个Path进行布尔运算(即取交集、并集等操作) -计算边界 | computeBounds | 计算Path的边界 -重置路径 | reset, rewind | 清除Path中的内容
**reset不保留内部数据结构,但会保留FillType.**
**rewind会保留内部的数据结构,但不保留FillType** -矩阵操作 | transform | 矩阵变换 +| 作用 | 相关方法 | 备注 | +| ----------- | ---------------------------------------- | ---------------------------------------- | +| 移动起点 | moveTo | 移动下一次操作的起点位置 | +| 设置终点 | setLastPoint | 重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同 | +| 连接直线 | lineTo | 添加上一个点到当前点之间的直线到Path | +| 闭合路径 | close | 连接第一个点连接到最后一个点,形成一个闭合区域 | +| 添加内容 | addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo | 添加(矩形, 圆角矩形, 椭圆, 圆, 路径, 圆弧) 到当前Path (注意addArc和arcTo的区别) | +| 是否为空 | isEmpty | 判断Path是否为空 | +| 是否为矩形 | isRect | 判断path是否是一个矩形 | +| 替换路径 | set | 用新的路径替换到当前路径所有内容 | +| 偏移路径 | offset | 对当前路径之前的操作进行偏移(不会影响之后的操作) | +| 贝塞尔曲线 | quadTo, cubicTo | 分别为二次和三次贝塞尔曲线的方法 | +| rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)** | +| 填充模式 | setFillType, getFillType, isInverseFillType, toggleInverseFillType | 设置,获取,判断和切换填充模式 | +| 提示方法 | incReserve | 提示Path还有多少个点等待加入**(这个方法貌似会让Path优化存储结构)** | +| 布尔操作(API19) | op | 对两个Path进行布尔运算(即取交集、并集等操作) | +| 计算边界 | computeBounds | 计算Path的边界 | +| 重置路径 | reset, rewind | 清除Path中的内容
**reset不保留内部数据结构,但会保留FillType.**
**rewind会保留内部的数据结构,但不保留FillType** | +| 矩阵操作 | transform | 矩阵变换 | ## 二.Path详解 @@ -64,14 +63,14 @@ rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是 以上几种类型中比较有用的就是基础型和实战型,但两者各有不足,本文会综合两者内容,从零开始学习贝塞尔曲线。 ### 第一步.理解贝塞尔曲线的原理 - + 此处理解贝塞尔曲线并非是学会公式的推导过程(不是推倒(ノ*・ω・)ノ),而是要了解贝塞尔曲线是如何生成的。 贝塞尔曲线是用一系列点来控制曲线状态的,我将这些点简单分为两类: - 类型 | 作用 --------|------ -数据点 | 确定曲线的起始和结束位置 -控制点 | 确定曲线的弯曲程度 +| 类型 | 作用 | +| ---- | ------------ | +| 数据点 | 确定曲线的起始和结束位置 | +| 控制点 | 确定曲线的弯曲程度 | > 此处暂时仅作了解概念,接下来就会讲解其中详细的含义。 @@ -101,7 +100,7 @@ rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是 ![](http://ww2.sinaimg.cn/large/005Xtdi2jw1f361oje6h1j308c0dwdg0.jpg) - + 连接DE,取点F,使得: @@ -131,7 +130,7 @@ rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是 #### 一阶曲线: -一阶曲线是一条线段,非常简单,可以参见上一篇文章[Path之基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_Basic.md),此处就不详细讲解了。 +一阶曲线是一条线段,非常简单,可以参见上一篇文章[Path之基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/5%5DPath_Basic.md),此处就不详细讲解了。 #### 二阶曲线: @@ -331,10 +330,10 @@ public class Bezier2 extends View { #### 降阶与升阶 -类型 | 释义 | 变化 ------|---|--- -降阶 | 在保持曲线形状与方向不变的情况下,减少控制点数量,即降低曲线阶数 | 方法变得简单,数据点变多,控制点可能减少,灵活性变弱 -升阶 | 在保持曲线形状与方向不变的情况下,增加控制点数量,即升高曲线阶数 | 方法更加复杂,数据点不变,控制点增加,灵活性变强 +| 类型 | 释义 | 变化 | +| ---- | -------------------------------- | -------------------------- | +| 降阶 | 在保持曲线形状与方向不变的情况下,减少控制点数量,即降低曲线阶数 | 方法变得简单,数据点变多,控制点可能减少,灵活性变弱 | +| 升阶 | 在保持曲线形状与方向不变的情况下,增加控制点数量,即升高曲线阶数 | 方法更加复杂,数据点不变,控制点增加,灵活性变强 | ### 第三步.贝塞尔曲线使用实例 @@ -342,12 +341,12 @@ public class Bezier2 extends View { > 需要绘制不规则图形时? 当然不是!目前来说,我觉得使用贝塞尔曲线主要有以下几个方面(仅个人拙见,可能存在错误,欢迎指正) -序号 | 内容 | 用例 ------|-----------------------------------------------|--------- - 1 | 事先不知道曲线状态,需要实时计算时 | 天气预报气温变化的平滑折线图 - 2 | 显示状态会根据用户操作改变时 | QQ小红点,仿真翻书效果 - 3 | 一些比较复杂的运动状态(配合PathMeasure使用) | 复杂运动状态的动画效果 - +| 序号 | 内容 | 用例 | +| ---- | ---------------------------- | -------------- | +| 1 | 事先不知道曲线状态,需要实时计算时 | 天气预报气温变化的平滑折线图 | +| 2 | 显示状态会根据用户操作改变时 | QQ小红点,仿真翻书效果 | +| 3 | 一些比较复杂的运动状态(配合PathMeasure使用) | 复杂运动状态的动画效果 | + 至于只需要一个静态的曲线图形的情况,用图片岂不是更好,大量的计算会很不划算。 如果是显示SVG矢量图的话,已经有相关的解析工具了(内部依旧运用的有贝塞尔曲线),不需要手动计算。 @@ -375,15 +374,15 @@ public class Bezier2 extends View { #### 核心难点: ##### 1.如何得到数据点和控制点的位置? - + 关于使用绘制圆形的数据点与控制点早就已经有人详细的计算好了,可以参考stackoverflow的一个回答[How to create circle with Bézier curves?](http://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves)其中的数据只需要拿来用即可。 - + 而对于心形的数据点和控制点,可以由圆形的部分数据点和控制点平移后得到,具体参数可以自己慢慢调整到一个满意的效果。 - + ##### 2.如何达到渐变效果? - + 渐变其实就是每次对数据点和控制点稍微移动一点,然后重绘界面,在短时间多次的调整数据点与控制点,使其逐渐接近目标值,通过不断的重绘界面达到一种渐变的效果。过程可以参照下图动态效果: - + ![](http://ww2.sinaimg.cn/large/005Xtdi2jw1f3ch74ewiig308c0e8wic.gif) #### 代码: diff --git a/CustomView/Advance/[07]Path_Over.md b/CustomView/Advance/[07]Path_Over.md index be9818b..a942b63 100644 --- a/CustomView/Advance/[07]Path_Over.md +++ b/CustomView/Advance/[07]Path_Over.md @@ -3,32 +3,32 @@ ### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop) ### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView/README.md) -经历过前两篇 [Path之基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_Basic.md) 和 [Path之贝塞尔曲线](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B6%5DPath_Bezier.md) 的讲解,本篇终于进入Path的收尾篇,本篇结束后Path的大部分相关方法都已经讲解完了,但Path还有一些更有意思的玩法,应该会在后续的文章中出现吧,嗯,应该会的ˊ_>ˋ +经历过前两篇 [Path之基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B05%5DPath_Basic.md) 和 [Path之贝塞尔曲线](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B06%5DPath_Bezier.md) 的讲解,本篇终于进入Path的收尾篇,本篇结束后Path的大部分相关方法都已经讲解完了,但Path还有一些更有意思的玩法,应该会在后续的文章中出现吧,嗯,应该会的ˊ_>ˋ ****** ## 一.Path常用方法表 > 为了兼容性(_偷懒_) 本表格中去除了在API21(即安卓版本5.0)以上才添加的方法。忍不住吐槽一下,为啥看起来有些顺手就能写的重载方法要等到API21才添加上啊。宝宝此刻内心也是崩溃的。 -作用 | 相关方法 | 备注 -----------------|-----------------|------------------------------------------ -移动起点 | moveTo | 移动下一次操作的起点位置 -设置终点 | setLastPoint | 重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同 -连接直线 | lineTo | 添加上一个点到当前点之间的直线到Path -闭合路径 | close | 连接第一个点连接到最后一个点,形成一个闭合区域 -添加内容 | addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo | 添加(矩形, 圆角矩形, 椭圆, 圆, 路径, 圆弧) 到当前Path (注意addArc和arcTo的区别) -是否为空 | isEmpty | 判断Path是否为空 -是否为矩形 | isRect | 判断path是否是一个矩形 -替换路径 | set | 用新的路径替换到当前路径所有内容 -偏移路径 | offset | 对当前路径之前的操作进行偏移(不会影响之后的操作) -贝塞尔曲线 | quadTo, cubicTo | 分别为二次和三次贝塞尔曲线的方法 -rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)** -填充模式 | setFillType, getFillType, isInverseFillType, toggleInverseFillType | 设置,获取,判断和切换填充模式 -提示方法 | incReserve | 提示Path还有多少个点等待加入**(这个方法貌似会让Path优化存储结构)** -布尔操作(API19) | op | 对两个Path进行布尔运算(即取交集、并集等操作) -计算边界 | computeBounds | 计算Path的边界 -重置路径 | reset, rewind | 清除Path中的内容
**reset不保留内部数据结构,但会保留FillType.**
**rewind会保留内部的数据结构,但不保留FillType** -矩阵操作 | transform | 矩阵变换 +| 作用 | 相关方法 | 备注 | +| ----------- | ---------------------------------------- | ---------------------------------------- | +| 移动起点 | moveTo | 移动下一次操作的起点位置 | +| 设置终点 | setLastPoint | 重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同 | +| 连接直线 | lineTo | 添加上一个点到当前点之间的直线到Path | +| 闭合路径 | close | 连接第一个点连接到最后一个点,形成一个闭合区域 | +| 添加内容 | addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo | 添加(矩形, 圆角矩形, 椭圆, 圆, 路径, 圆弧) 到当前Path (注意addArc和arcTo的区别) | +| 是否为空 | isEmpty | 判断Path是否为空 | +| 是否为矩形 | isRect | 判断path是否是一个矩形 | +| 替换路径 | set | 用新的路径替换到当前路径所有内容 | +| 偏移路径 | offset | 对当前路径之前的操作进行偏移(不会影响之后的操作) | +| 贝塞尔曲线 | quadTo, cubicTo | 分别为二次和三次贝塞尔曲线的方法 | +| rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)** | +| 填充模式 | setFillType, getFillType, isInverseFillType, toggleInverseFillType | 设置,获取,判断和切换填充模式 | +| 提示方法 | incReserve | 提示Path还有多少个点等待加入**(这个方法貌似会让Path优化存储结构)** | +| 布尔操作(API19) | op | 对两个Path进行布尔运算(即取交集、并集等操作) | +| 计算边界 | computeBounds | 计算Path的边界 | +| 重置路径 | reset, rewind | 清除Path中的内容
**reset不保留内部数据结构,但会保留FillType.**
**rewind会保留内部的数据结构,但不保留FillType** | +| 矩阵操作 | transform | 矩阵变换 | ## 二、Path方法详解 @@ -79,10 +79,10 @@ rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是 > PS:此处所有的图形均为封闭图形,不包括图形不封闭这种情况。 -方法 | 判定条件 | 解释 ----------------|-----------------------------------------------|---------------- -奇偶规则 | 奇数表示在图形内,偶数表示在图形外 | 从任意位置p作一条射线, 若与该射线相交的图形边的数目为奇数,则p是图形内部点,否则是外部点。 -非零环绕数规则 | 若环绕数为0表示在图形外,非零表示在图形内 | 首先使图形的边变为矢量。将环绕数初始化为零。再从任意位置p作一条射线。当从p点沿射线方向移动时,对在每个方向上穿过射线的边计数,每当图形的边从右到左穿过射线时,环绕数加1,从左到右时,环绕数减1。处理完图形的所有相关边之后,若环绕数为非零,则p为内部点,否则,p是外部点。 +| 方法 | 判定条件 | 解释 | +| ------- | --------------------- | ---------------------------------------- | +| 奇偶规则 | 奇数表示在图形内,偶数表示在图形外 | 从任意位置p作一条射线, 若与该射线相交的图形边的数目为奇数,则p是图形内部点,否则是外部点。 | +| 非零环绕数规则 | 若环绕数为0表示在图形外,非零表示在图形内 | 首先使图形的边变为矢量。将环绕数初始化为零。再从任意位置p作一条射线。当从p点沿射线方向移动时,对在每个方向上穿过射线的边计数,每当图形的边从右到左穿过射线时,环绕数加1,从左到右时,环绕数减1。处理完图形的所有相关边之后,若环绕数为非零,则p为内部点,否则,p是外部点。 | 接下来我们先了解一下两种判断方法是如何工作的。 @@ -95,16 +95,16 @@ rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是 在上图中有一个四边形,我们选取了三个点来判断这些点是否在图形内部。 > -P1: 从P1发出一条射线,发现图形与该射线相交边数为0,偶数,故P1点在图形外部。
-P2: 从P2发出一条射线,发现图形与该射线相交边数为1,奇数,故P2点在图形内部。
-P3: 从P3发出一条射线,发现图形与该射线相交边数为2,偶数,故P3点在图形外部。
+>P1: 从P1发出一条射线,发现图形与该射线相交边数为0,偶数,故P1点在图形外部。
+>P2: 从P2发出一条射线,发现图形与该射线相交边数为1,奇数,故P2点在图形内部。
+>P3: 从P3发出一条射线,发现图形与该射线相交边数为2,偶数,故P3点在图形外部。
#### 非零环绕数规则(Non-Zero Winding Number Rule) 非零环绕数规则相对来说比较难以理解一点。 -我们在之前的文章 [Path之基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_Basic.md) 中我们了解到,在给Path中添加图形时需要指定图形的添加方式,是用顺时针还是逆时针,另外我们不论是使用lineTo,quadTo,cubicTo还是其他连接线的方法,都是从一个点连接到另一个点,换言之,**Path中任何线段都是有方向性的**,这也是使用非零环绕数规则的基础。 +我们在之前的文章 [Path之基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B05%5DPath_Basic.md) 中我们了解到,在给Path中添加图形时需要指定图形的添加方式,是用顺时针还是逆时针,另外我们不论是使用lineTo,quadTo,cubicTo还是其他连接线的方法,都是从一个点连接到另一个点,换言之,**Path中任何线段都是有方向性的**,这也是使用非零环绕数规则的基础。 我们依旧用一个简单的例子来说明非零环绕数规则的用法: @@ -113,9 +113,9 @@ P3: 从P3发出一条射线,发现图形与该射线相交边数为2,偶数 ![](http://ww2.sinaimg.cn/large/005Xtdi2jw1f42368af2jj308c0dwt8z.jpg) > -P1: 从P1点发出一条射线,沿射线防线移动,并没有与边相交点部分,环绕数为0,故P1在图形外边。
-P2: 从P2点发出一条射线,沿射线方向移动,与图形点左侧边相交,该边从左到右穿过穿过射线,环绕数-1,最终环绕数为-1,故P2在图形内部。
-P3: 从P3点发出一条射线,沿射线方向移动,在第一个交点处,底边从右到左穿过射线,环绕数+1,在第二个交点处,右侧边从左到右穿过射线,环绕数-1,最终环绕数为0,故P3在图形外部。
+>P1: 从P1点发出一条射线,沿射线防线移动,并没有与边相交点部分,环绕数为0,故P1在图形外边。
+>P2: 从P2点发出一条射线,沿射线方向移动,与图形点左侧边相交,该边从左到右穿过穿过射线,环绕数-1,最终环绕数为-1,故P2在图形内部。
+>P3: 从P3点发出一条射线,沿射线方向移动,在第一个交点处,底边从右到左穿过射线,环绕数+1,在第二个交点处,右侧边从左到右穿过射线,环绕数-1,最终环绕数为0,故P3在图形外部。
通常,这两种方法的判断结果是相同的,但也存在两种方法判断结果不同的情况,如下面这种情况: @@ -135,12 +135,12 @@ P3: 从P3点发出一条射线,沿射线方向移动,在第一个交点处 Android中的填充模式有四种,是封装在Path中的一个枚举。 -模式 | 简介 ------------------|----------------------- -EVEN_ODD | 奇偶规则 -INVERSE_EVEN_ODD | 反奇偶规则 -WINDING | 非零环绕数规则 -INVERSE_WINDING | 反非零环绕数规则 +| 模式 | 简介 | +| ---------------- | -------- | +| EVEN_ODD | 奇偶规则 | +| INVERSE_EVEN_ODD | 反奇偶规则 | +| WINDING | 非零环绕数规则 | +| INVERSE_WINDING | 反非零环绕数规则 | 我们可以看到上面有四种模式,分成两对,例如 "奇偶规则" 与 "反奇偶规则" 是一对,它们之间有什么关系呢? @@ -150,12 +150,12 @@ Inverse 和含义是“相反,对立”,说明反奇偶规则刚好与奇偶 > 这些都是Path中的方法。 -方法 | 作用 -------------------------|---------------------------- -setFillType | 设置填充规则 -getFillType | 获取当前填充规则 -isInverseFillType | 判断是否是反向(INVERSE)规则 -toggleInverseFillType | 切换填充规则(即原有规则与反向规则之间相互切换) +| 方法 | 作用 | +| --------------------- | ------------------------ | +| setFillType | 设置填充规则 | +| getFillType | 获取当前填充规则 | +| isInverseFillType | 判断是否是反向(INVERSE)规则 | +| toggleInverseFillType | 切换填充规则(即原有规则与反向规则之间相互切换) | #### 示例演示: @@ -247,13 +247,13 @@ toggleInverseFillType | 切换填充规则(即原有规则与反向规则之 Path的布尔运算有五种逻辑,如下: -逻辑名称 | 类比 | 说明 | 示意图 --------------------|------|----------------------------------------|------------------------- -DIFFERENCE | 差集 | Path1中减去Path2后剩下的部分 | ![](http://ww2.sinaimg.cn/large/005Xtdi2gw1f43j85gcaqj305k03c0sn.jpg) -REVERSE_DIFFERENCE | 差集 | Path2中减去Path1后剩下的部分 | ![](http://ww2.sinaimg.cn/large/005Xtdi2gw1f43jbaaw80j305k03c0sn.jpg) -INTERSECT | 交集 | Path1与Path2相交的部分 | ![](http://ww3.sinaimg.cn/large/005Xtdi2gw1f43jbj4iddj305k03c746.jpg) -UNION | 并集 | 包含全部Path1和Path2 | ![](http://ww2.sinaimg.cn/large/005Xtdi2gw1f43jbqk8rbj305k03cmx4.jpg) -XOR | 异或 | 包含Path1与Path2但不包括两者相交的部分 | ![](http://ww3.sinaimg.cn/large/005Xtdi2gw1f43jby8c60j305k03c0sp.jpg) +| 逻辑名称 | 类比 | 说明 | 示意图 | +| ------------------ | ---- | ------------------------ | ---------------------------------------- | +| DIFFERENCE | 差集 | Path1中减去Path2后剩下的部分 | ![](http://ww2.sinaimg.cn/large/005Xtdi2gw1f43j85gcaqj305k03c0sn.jpg) | +| REVERSE_DIFFERENCE | 差集 | Path2中减去Path1后剩下的部分 | ![](http://ww2.sinaimg.cn/large/005Xtdi2gw1f43jbaaw80j305k03c0sn.jpg) | +| INTERSECT | 交集 | Path1与Path2相交的部分 | ![](http://ww3.sinaimg.cn/large/005Xtdi2gw1f43jbj4iddj305k03c746.jpg) | +| UNION | 并集 | 包含全部Path1和Path2 | ![](http://ww2.sinaimg.cn/large/005Xtdi2gw1f43jbqk8rbj305k03cmx4.jpg) | +| XOR | 异或 | 包含Path1与Path2但不包括两者相交的部分 | ![](http://ww3.sinaimg.cn/large/005Xtdi2gw1f43jby8c60j305k03c0sp.jpg) | #### 布尔运算方法 @@ -282,7 +282,7 @@ XOR | 异或 | 包含Path1与Path2但不包括两者相交的部 代码: -``` java +​``` java int x = 80; int r = 100; @@ -331,10 +331,10 @@ XOR | 异或 | 包含Path1与Path2但不包括两者相交的部 它有两个参数: -参数 | 作用 --------|-------- -bounds | 测量结果会放入这个矩形 -exact | 是否精确测量,目前这一个参数作用已经废弃,一般写true即可。 +| 参数 | 作用 | +| ------ | ------------------------------- | +| bounds | 测量结果会放入这个矩形 | +| exact | 是否精确测量,目前这一个参数作用已经废弃,一般写true即可。 | 关于exact如有疑问可参见Google官方的提交记录[Path.computeBounds()](https://code.google.com/p/android/issues/detail?id=4070) @@ -371,10 +371,10 @@ exact | 是否精确测量,目前这一个参数作用已经废弃,一般 重置Path有两个方法,分别是reset和rewind,两者区别主要有一下两点: -方法 | 是否保留FillType设置 | 是否保留原有数据结构 --------|:--------------------:|:--------------------: -reset | 是 | 否 -rewind | 否 | 是 +| 方法 | 是否保留FillType设置 | 是否保留原有数据结构 | +| ------ | :------------: | :--------: | +| reset | 是 | 否 | +| rewind | 否 | 是 | **这个两个方法应该何时选择呢?** @@ -384,7 +384,7 @@ _因为“FillType”影响的是显示效果,而“数据结构”影响的 ## 总结 - + Path中常用的方法到此已经结束,希望能够帮助大家加深对Path对理解运用,让大家能够用Path愉快的玩耍。( ̄▽ ̄) (,,• ₃ •,,) diff --git a/CustomView/Advance/[08]Path_Play.md b/CustomView/Advance/[08]Path_Play.md index 181158c..3c6e342 100644 --- a/CustomView/Advance/[08]Path_Play.md +++ b/CustomView/Advance/[08]Path_Play.md @@ -5,9 +5,9 @@ 可以看到,在经过 -[Path之基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_Basic.md) -[Path之贝塞尔曲线](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B6%5DPath_Bezier.md) 和 -[Path之完结篇(伪)](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B7%5DPath_Over.md) 后, Path中各类方法基本上都讲完了,表格中还没有讲解到到方法就是矩阵变换了,难道本篇终于要讲矩阵了? +[Path之基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B05%5DPath_Basic.md) +[Path之贝塞尔曲线](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B06%5DPath_Bezier.md) 和 +[Path之完结篇(伪)](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B07%5DPath_Over.md) 后, Path中各类方法基本上都讲完了,表格中还没有讲解到到方法就是矩阵变换了,难道本篇终于要讲矩阵了? 非也,矩阵这一部分仍在后面单独讲解,本篇主要讲解 PathMeasure 这个类与 Path 的一些使用技巧。 > PS:不要问我为什么不讲 PathEffect,因为这个方法在后面的Paint系列中。 @@ -24,22 +24,22 @@ ### 构造方法 -方法名 | 释义 ----|--- -PathMeasure() | 创建一个空的PathMeasure -PathMeasure(Path path, boolean forceClosed) | 创建 PathMeasure 并关联一个指定的Path(Path需要已经创建完成)。 +| 方法名 | 释义 | +| ---------------------------------------- | ---------------------------------------- | +| PathMeasure() | 创建一个空的PathMeasure | +| PathMeasure(Path path, boolean forceClosed) | 创建 PathMeasure 并关联一个指定的Path(Path需要已经创建完成)。 | ### 公共方法 -返回值 | 方法名 | 释义 ---------|--------------------------------------------------------------------------|------------------- -void | setPath(Path path, boolean forceClosed) | 关联一个Path -boolean | isClosed() | 是否闭合 -float | getLength() | 获取Path的长度 -boolean | nextContour() | 跳转到下一个轮廓 -boolean | getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) | 截取片段 -boolean | getPosTan(float distance, float[] pos, float[] tan) | 获取指定长度的位置坐标及该点切线值 -boolean | getMatrix(float distance, Matrix matrix, int flags) | 获取指定长度的位置坐标及该点Matrix +| 返回值 | 方法名 | 释义 | +| ------- | ---------------------------------------- | -------------------- | +| void | setPath(Path path, boolean forceClosed) | 关联一个Path | +| boolean | isClosed() | 是否闭合 | +| float | getLength() | 获取Path的长度 | +| boolean | nextContour() | 跳转到下一个轮廓 | +| boolean | getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) | 截取片段 | +| boolean | getPosTan(float distance, float[] pos, float[] tan) | 获取指定长度的位置坐标及该点切线值 | +| boolean | getMatrix(float distance, Matrix matrix, int flags) | 获取指定长度的位置坐标及该点Matrix | PathMeasure的方法也不多,接下来我们就逐一的讲解一下。 @@ -138,13 +138,13 @@ getSegment 用于获取Path的一个片段,方法如下: 方法各个参数释义: -参数 | 作用 | 备注 -----------------|----------------------------------|-------------------------------------------- -返回值(boolean) | 判断截取是否成功 | true 表示截取成功,结果存入dst中,false 截取失败,不会改变dst中内容 -startD | 开始截取位置距离 Path 起点的长度 | 取值范围: 0 <= startD < stopD <= Path总长度 -stopD | 结束截取位置距离 Path 起点的长度 | 取值范围: 0 <= startD < stopD <= Path总长度 -dst | 截取的 Path 将会添加到 dst 中 | 注意: 是添加,而不是替换 -startWithMoveTo | 起始点是否使用 moveTo | 用于保证截取的 Path 第一个点位置不变 +| 参数 | 作用 | 备注 | +| --------------- | -------------------- | ---------------------------------------- | +| 返回值(boolean) | 判断截取是否成功 | true 表示截取成功,结果存入dst中,false 截取失败,不会改变dst中内容 | +| startD | 开始截取位置距离 Path 起点的长度 | 取值范围: 0 <= startD < stopD <= Path总长度 | +| stopD | 结束截取位置距离 Path 起点的长度 | 取值范围: 0 <= startD < stopD <= Path总长度 | +| dst | 截取的 Path 将会添加到 dst 中 | 注意: 是添加,而不是替换 | +| startWithMoveTo | 起始点是否使用 moveTo | 用于保证截取的 Path 第一个点位置不变 | > * 如果 startD、stopD 的数值不在取值范围 [0, getLength] 内,或者 startD == stopD 则返回值为 false,不会改变 dst 内容。 @@ -230,10 +230,10 @@ startWithMoveTo | 起始点是否使用 moveTo | 用于保证截取 从而我们可以用以下规则来判断 startWithMoveTo 的取值: -取值 | 主要功用 -------|------------------ -true | 保证截取得到的 Path 片段不会发生形变 -false | 保证存储截取片段的 Path(dst) 的连续性 +| 取值 | 主要功用 | +| ----- | ------------------------ | +| true | 保证截取得到的 Path 片段不会发生形变 | +| false | 保证存储截取片段的 Path(dst) 的连续性 | @@ -296,12 +296,12 @@ log输出结果: 方法各个参数释义: -参数 | 作用 | 备注 -----------------|----------------------------------|-------------------------------------------- -返回值(boolean) | 判断获取是否成功 | true表示成功,数据会存入 pos 和 tan 中,
false 表示失败,pos 和 tan 不会改变 -distance | 距离 Path 起点的长度 | 取值范围: 0 <= distance <= getLength -pos | 该点的坐标值 | 坐标值: (x==[0], y==[1]) -tan | 该点的正切值 | 正切值: (x==[0], y==[1]) +| 参数 | 作用 | 备注 | +| ------------ | ------------- | ---------------------------------------- | +| 返回值(boolean) | 判断获取是否成功 | true表示成功,数据会存入 pos 和 tan 中,
false 表示失败,pos 和 tan 不会改变 | +| distance | 距离 Path 起点的长度 | 取值范围: 0 <= distance <= getLength | +| pos | 该点的坐标值 | 坐标值: (x==[0], y==[1]) | +| tan | 该点的正切值 | 正切值: (x==[0], y==[1]) | 这个方法也不难理解,除了其中 `tan` 这个东东,这个东西是干什么的呢? @@ -387,12 +387,12 @@ boolean getMatrix (float distance, Matrix matrix, int flags) 方法各个参数释义: -参数 | 作用 | 备注 -----------------|----------------------------------|-------------------------------------------- -返回值(boolean) | 判断获取是否成功 | true表示成功,数据会存入matrix中,false 失败,matrix内容不会改变 -distance | 距离 Path 起点的长度 | 取值范围: 0 <= distance <= getLength -matrix | 根据 falgs 封装好的matrix | 会根据 flags 的设置而存入不同的内容 -flags | 规定哪些内容会存入到matrix中 | 可选择
POSITION_MATRIX_FLAG(位置)
ANGENT_MATRIX_FLAG(正切) +| 参数 | 作用 | 备注 | +| ------------ | ------------------- | ---------------------------------------- | +| 返回值(boolean) | 判断获取是否成功 | true表示成功,数据会存入matrix中,false 失败,matrix内容不会改变 | +| distance | 距离 Path 起点的长度 | 取值范围: 0 <= distance <= getLength | +| matrix | 根据 falgs 封装好的matrix | 会根据 flags 的设置而存入不同的内容 | +| flags | 规定哪些内容会存入到matrix中 | 可选择
POSITION_MATRIX_FLAG(位置)
ANGENT_MATRIX_FLAG(正切) | 其实这个方法就相当于我们在前一个例子中封装 `matrix` 的过程由 `getMatrix` 替我们做了,我们可以直接得到一个封装好到 `matrix`,岂不快哉。 @@ -447,17 +447,17 @@ measure.getMatrix(distance, matrix, PathMeasure.TANGENT_MATRIX_FLAG | PathMeasur 我们知道,用Path可以创建出各种个样的图形,但如果图形过于复杂时,用代码写就不现实了,不仅麻烦,而且容易出错,所以在绘制复杂的图形时我们一般是将 SVG 图像转换为 Path。 **你说什么是 SVG?** - + SVG 是一种矢量图,内部用的是 xml 格式化存储方式存储这操作和数据,你完全可以将 SVG 看作是 Path 的各项操作简化书写后的存储格式。 - + Path 和 SVG 结合通常能诞生出一些奇妙的东西,如下: ![](http://ww3.sinaimg.cn/large/005Xtdi2jw1f4g87vfjbeg30690b4go8.gif) ![](http://ww3.sinaimg.cn/large/005Xtdi2jw1f4g89vqhqwg30690b4mzu.gif) > -**该图片来自这个开源库 ->[PathView](https://github.com/geftimov/android-pathview)**
-**SVG 转 Path 的解析可以用这个库 -> [AndroidSVG](https://bigbadaboom.github.io/androidsvg/)** +>**该图片来自这个开源库 ->[PathView](https://github.com/geftimov/android-pathview)**
+>**SVG 转 Path 的解析可以用这个库 -> [AndroidSVG](https://bigbadaboom.github.io/androidsvg/)** 限于篇幅以及本人精力,这一部分就暂不详解了,感兴趣的可以直接看源码,或者搜索一些相关的解析文章。 @@ -468,7 +468,7 @@ Path 和 SVG 结合通常能诞生出一些奇妙的东西,如下: **话说本篇文章的名字不是叫 玩出花样么?怎么只见前面啰啰嗦嗦的扯了一大堆不明所以的东西,花样在哪里?** > -**前面的内容虽然啰嗦繁杂,但却是重中之重的基础,如果在修仙界,这叫根基,而下面讲述的内容的是招式,有了根基才能演化出千变万化的招式,而没有根基只学招式则是徒有其表,只能学一样会一样,很难适应千变万化的需求。** +>**前面的内容虽然啰嗦繁杂,但却是重中之重的基础,如果在修仙界,这叫根基,而下面讲述的内容的是招式,有了根基才能演化出千变万化的招式,而没有根基只学招式则是徒有其表,只能学一样会一样,很难适应千变万化的需求。** 先放一个效果图,然后分析一下实现过程: @@ -476,12 +476,12 @@ Path 和 SVG 结合通常能诞生出一些奇妙的东西,如下: 这是一个搜索的动效图,通过分析可以得到它应该有四种状态,分别如下: -状态 |概述 ----------|-------------------------------------------------- -初始状态 | 初始状态,没有任何动效,只显示一个搜索标志 :mag: -准备搜索 | 放大镜图标逐渐变化为一个点 -正在搜索 | 围绕这一个圆环运动,并且线段长度会周期性变化 -准备结束 | 从一个点逐渐变化成为放大镜图标 +| 状态 | 概述 | +| ---- | --------------------------- | +| 初始状态 | 初始状态,没有任何动效,只显示一个搜索标志 :mag: | +| 准备搜索 | 放大镜图标逐渐变化为一个点 | +| 正在搜索 | 围绕这一个圆环运动,并且线段长度会周期性变化 | +| 准备结束 | 从一个点逐渐变化成为放大镜图标 | 这些状态是有序转换的,转换流程以及转换条件如下: diff --git a/CustomView/Advance/[09]Matrix_Basic.md b/CustomView/Advance/[09]Matrix_Basic.md index 044cbaf..b4f4b34 100644 --- a/CustomView/Advance/[09]Matrix_Basic.md +++ b/CustomView/Advance/[09]Matrix_Basic.md @@ -18,12 +18,12 @@

## 前言 -本文内容偏向理论,和 [画布操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B3%5DCanvas_Convert.md) 有重叠的部分,本文会让你更加深入的了解其中的原理。 +本文内容偏向理论,和 [画布操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B03%5DCanvas_Convert.md) 有重叠的部分,本文会让你更加深入的了解其中的原理。 本篇的主角Matrix,是一个一直在后台默默工作的劳动模范,虽然我们所有看到View背后都有着Matrix的功劳,但我们却很少见到它,本篇我们就看看它是何方神圣吧。 > -由于Google已经对这一部分已经做了很好的封装,所以跳过本部分对实际开发影响并不会太大,不想深究的粗略浏览即可,下一篇中将会详细讲解Matrix的具体用法和技巧。 +>由于Google已经对这一部分已经做了很好的封装,所以跳过本部分对实际开发影响并不会太大,不想深究的粗略浏览即可,下一篇中将会详细讲解Matrix的具体用法和技巧。 ****** @@ -138,13 +138,13 @@ y_0 \\\\ \\right ] $$) -> -你可能注意到了,我们坐标多了一个1,这是使用了齐次坐标系的缘故,在数学中我们的点和向量都是这样表示的(x, y),两者看起来一样,计算机无法区分,为此让计算机也可以区分它们,增加了一个标志位,增加之后看起来是这样:
> -(x, y, 1) - 点
-(x, y, 0) - 向量
+> 你可能注意到了,我们坐标多了一个1,这是使用了齐次坐标系的缘故,在数学中我们的点和向量都是这样表示的(x, y),两者看起来一样,计算机无法区分,为此让计算机也可以区分它们,增加了一个标志位,增加之后看起来是这样:
> -另外,齐次坐标具有等比的性质,(2,3,1)、(4,6,2)...(2N,3N,N)表示的均是(2,3)这一个点。(**将MPERSP_2解释为scale这一误解就源于此**)。 +> (x, y, 1) - 点
+> (x, y, 0) - 向量
+> +> 另外,齐次坐标具有等比的性质,(2,3,1)、(4,6,2)...(2N,3N,N)表示的均是(2,3)这一个点。(**将MPERSP_2解释为scale这一误解就源于此**)。 图例: @@ -328,8 +328,8 @@ $$) ### 4.平移(Translate) -> -此处也是使用齐次坐标的优点体现之一,实际上前面的三个操作使用 2x2 的矩阵也能满足需求,但是使用 2x2 的矩阵,无法将平移操作加入其中,而将坐标扩展为齐次坐标后,将矩阵扩展为 3x3 就可以将算法统一,四种算法均可以使用矩阵乘法完成。 +> +> 此处也是使用齐次坐标的优点体现之一,实际上前面的三个操作使用 2x2 的矩阵也能满足需求,但是使用 2x2 的矩阵,无法将平移操作加入其中,而将坐标扩展为齐次坐标后,将矩阵扩展为 3x3 就可以将算法统一,四种算法均可以使用矩阵乘法完成。 ![](http://latex.codecogs.com/png.latex?$$ x = x_0 + \\Delta x $$) @@ -616,16 +616,16 @@ $$) 这个方法表,暂时放到这里让大家看看,方法的使用讲解放在下一篇文章中。 -方法类别 | 相关API | 摘要 ------------|---------------------------------------------------------|------------------------ -基本方法 | equals hashCode toString toShortString | 比较、 获取哈希值、 转换为字符串 -数值操作 | set reset setValues getValues | 设置、 重置、 设置数值、 获取数值 -数值计算 | mapPoints mapRadius mapRect mapVectors | 计算变换后的数值 -设置(set) | setConcat setRotate setScale setSkew setTranslate | 设置变换 -前乘(pre) | preConcat preRotate preScale preSkew preTranslate | 前乘变换 -后乘(post) | postConcat postRotate postScale postSkew postTranslate | 后乘变换 -特殊方法 | setPolyToPoly setRectToRect rectStaysRect setSinCos | 一些特殊操作 -矩阵相关 | invert isAffine isIdentity | 求逆矩阵、 是否为仿射矩阵、 是否为单位矩阵 ... +| 方法类别 | 相关API | 摘要 | +| -------- | ---------------------------------------- | -------------------------- | +| 基本方法 | equals hashCode toString toShortString | 比较、 获取哈希值、 转换为字符串 | +| 数值操作 | set reset setValues getValues | 设置、 重置、 设置数值、 获取数值 | +| 数值计算 | mapPoints mapRadius mapRect mapVectors | 计算变换后的数值 | +| 设置(set) | setConcat setRotate setScale setSkew setTranslate | 设置变换 | +| 前乘(pre) | preConcat preRotate preScale preSkew preTranslate | 前乘变换 | +| 后乘(post) | postConcat postRotate postScale postSkew postTranslate | 后乘变换 | +| 特殊方法 | setPolyToPoly setRectToRect rectStaysRect setSinCos | 一些特殊操作 | +| 矩阵相关 | invert isAffine isIdentity | 求逆矩阵、 是否为仿射矩阵、 是否为单位矩阵 ... |

## 总结