zoukankan      html  css  js  c++  java
  • 自定义view(14)使用Path绘制复杂图形

    灵活使用 Path ,可以画出复杂图形,就像美术生在画板上画复杂图形一样。程序员也可以用代码实现。

    1.样板图片

    这个是个温度计,它是静态的,温度值是动态变化的,所以要自定义个view.动态显示值,温度过高、过低时有警示功能。

    2.代码

      https://github.com/f9q/tempView

    3.Path类的关键api

    3.1 绝对绘制系列

    • void moveTo(float x, float y)

        将画笔移动到x,y

    • void lineTo(float x, float y)

        连接当前点到目标点dp(x,y),画一条线。

    • void arcTo(RectF oval, float startAngle, float sweepAngle)

        从当前点开始画弧,startAngle是順时针起始角度,sweepAngle是扫过角度(按360求模)。如果oval的起点不是当前path的最后一个点,则连接最后一个点到oval的起点。

    • void quadTo(float x1, float y1, float x2, float y2)

        假设最后个点是op(10,20),如果没有用MoveTo指定,默认点是(0,0),画一条经过 op、控制点cp(x1,y1)、终点ep(x2,y2)的贝塞尔曲线. 

    • void cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)

        与quadTo相似,只不过多个控制点cp2(x2,y2)

    3.2 相对绘制系列

    •  void rMoveTo(float dx, float dy)

        假设前个点是op(10,20),将画笔移动到目标点dp(dx,dy), 其中dx是相对10的偏移量,dy是相对20的偏移量。

    •  void rLineTo(float dx, float dy)

        假设前个点是op(10,20), 连接当前点到目标点dp(dx,dy),画一条线。其中dx是相对10的偏移量,dy是相对20的偏移量

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

        假设前个点是op(10,20),默认点是(0,0),画一条经过op、控制点cp(dx1,dy1)、终点ep(dx2,dy2)的贝塞尔曲线。dx1,dx2是相对前个点10的x偏移量,可为负。

    dy1,dy2是相对前个点20的y偏移量,可为负。

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

        与rQuadTo相似。也是多个了个控制点cp2(x2,y2)

    3.3 添加图形系列

    • void addRect(RectF rect, Direction dir)

        在路径上添加一个矩形、第2个参数是添加矩形的绘制方向,

      • Direction.CW 顺时针
      • Direction.CCW 逆时针
    • void addRoundRect(RectF rect, float rx, float ry, Direction dir)

        与上一个相似,添加的是圆角矩形。dir是纵向方向,如上。

    • void addOval(RectF oval, Direction dir) 

        添加一个椭圆,dir是纵向方向,如上。

    • void addCircle(float x, float y, float radius, Direction dir)

        添加一个圆圈,radius半径,dir是纵向方向。如上。

    • void addArc(RectF oval, float startAngle, float sweepAngle)

        添加一个弧线,startAngle是順时针起始角度,sweepAngle是扫过角度(按360求模)。

    • void addPath(Path src, float dx, float dy) 

        在当前路径上添加一个新的路径,dx,dy是相对最后一个点的x,y偏移量。

    3.4 路径设置系列

    • void transform(Matrix matrix, Path dst)

        把当前路径按matrix变形,如果dst不空,复制一分到dst中。

    • void reset()

        清空path对象数据和轨迹。保留FillType。

    • void rewind()

      清空所绘制的轨迹,但保留对象内部数据。方便下次快速复用。 不保留FillType。

    • void setFillType(FillType ft) 

      这个比较复杂,见5.path.setFillType(FillType ft) 

    • void close()

        闭合路径,如果执行闭合操作时当前点不和第1个点重合,则会画出一条线。

    • void offset(float dx, float dy)

        当前路径整体(所有图形)平移。

    4.Path特效

      可以给path添加各种特效,如虚线,离散等等。

    4.1 未指定特效的样子

     

    4.2 CornerPathEffect

    效果:将路径的转角变成圆角。

     

    代码:

    1    paint.setPathEffect(new CornerPathEffect(30));

    参数:

      圆角的半径。

    4.3 DiscretePathEffect

    效果:离散路径。

    代码:

    1   paint.setPathEffect(new DiscretePathEffect(3.0f, 10.0f));

    参数:

        /**
         * Chop the path into lines of segmentLength, randomly deviating from the
         * original path by deviation.
         */
    • 第1个参数是横向两个离散点的间距。
    • 第2个参数是纵向随机离散的最大距离。

    4.4 DashPathEffect

    效果:虚线效果。

     

    代码:

    1     float intervals[] = {1,5,10,15};
    2     paint.setStrokeWidth(5);
    3     paint.setStyle(Paint.Style.STROKE);
    4     paint.setPathEffect(new DashPathEffect(intervals, 3));

    DashPathEffect参数的含义:

         /**
         * The intervals array must contain an even number of entries (>=2), with
         * the even indices specifying the "on" intervals, and the odd indices
         * specifying the "off" intervals. phase is an offset into the intervals
         * array (mod the sum of all of the intervals). The intervals array
         * controls the length of the dashes. The paint's strokeWidth controls the
         * thickness of the dashes.
         * Note: this patheffect only affects drawing with the paint's style is set
         * to STROKE or FILL_AND_STROKE. It is ignored if the drawing is done with
         * style == FILL.
         * @param intervals array of ON and OFF distances
         * @param phase offset into the intervals array
         */
    • 第1个参数

        控制虚线的长度与间隙,数组长度不能小于2个,偶数位表示实线线段的长度(上面数组中的1、10),奇数位表示间隙的长度(上面数组中的5、15)。

    • 第2个参数

        控制虚线第1段是线段还是间隙,按第1个参数的长度求模。

      注意:这个特效只有在 paint的风格是 STROKE 和 FILL_AND_STROKE 时有效。

    4.5 PathDashPathEffect

    效果:指定虚线上的每个线段的图形为另一个路径。

    代码:

    1     Path rectDash = new Path();
    2     rectDash.addRect(0, 0, 10,10, Path.Direction.CW);
    3     paint.setPathEffect(new PathDashPathEffect(rectDash,20,1, PathDashPathEffect.Style.MORPH));

    参数:

    • 第1个参数是虚线段的图形。
    • 第2个参数是间隙的距离。
    • 第3个参数指定路径的下标。
    • 第4个参数是图形路径的绘制样式。有
      MORPH、ROTATE、TRANSLATE 3种。

    4.6 ComposePathEffect

    效果:组合效果

    代码:

    1         float intervals[] = {1,5,10,15};
    2         DiscretePathEffect discrete = new DiscretePathEffect(3.0f, 10.0f);
    3         DashPathEffect dash = new DashPathEffect(intervals, 3) ;
    4         ComposePathEffect compose = new ComposePathEffect(discrete,dash);
    5         paint.setPathEffect(compose);

    参数:

        /**
         * Construct a PathEffect whose effect is to apply first the inner effect
         * and the the outer pathEffect (e.g. outer(inner(path))).
         */
        public ComposePathEffect(PathEffect outerpe, PathEffect innerpe) {
            native_instance = nativeCreate(outerpe.native_instance,
                                           innerpe.native_instance);
        }

      第1个路径和第2个路径。先画出innerpe的效果,接着在innerpe的基础上增加outerpe效果!

    4.7 SumPathEffect

    效果:叠加效果

    代码:

    1         float intervals[] = {1,5,10,15};
    2         DiscretePathEffect discrete = new DiscretePathEffect(3.0f, 10.0f);
    3         DashPathEffect dash = new DashPathEffect(intervals, 3) ;
    4         SumPathEffect sum = new SumPathEffect(discrete,dash);
    5         paint.setPathEffect(sum);

    参数:

        /**
         * Construct a PathEffect whose effect is to apply two effects, in sequence.
         * (e.g. first(path) + second(path))
         */
        public SumPathEffect(PathEffect first, PathEffect second) {
            native_instance = nativeCreate(first.native_instance,
                                           second.native_instance);
        }

      先画出first的效果,接着绘制second效果!将两个效果简单的重叠在一起显示出来!

    5.path.setFillType(FillType ft)

    5.1 作用

      它指定计算路径内部区域的算法。如何判断点在图形内外,一般有两种:奇偶算法和非零环绕数算法。

    5.2 相关源码

     1 /**
     2      * Set the path's fill type. This defines how "inside" is computed.
     3      *
     4      * @param ft The new fill type for this path
     5      */
     6     public void setFillType(FillType ft) {
     7         nSetFillType(mNativePath, ft.nativeInt);
     8     }
     9     /**
    10      * Enum for the ways a path may be filled.
    11      */
    12     public enum FillType {
    13         // these must match the values in SkPath.h
    14         /**
    15          * Specifies that "inside" is computed by a non-zero sum of signed
    16          * edge crossings.
    17          */
    18         WINDING         (0),
    19         /**
    20          * Specifies that "inside" is computed by an odd number of edge
    21          * crossings.
    22          */
    23         EVEN_ODD        (1),
    24         /**
    25          * Same as {@link #WINDING}, but draws outside of the path, rather than inside.
    26          */
    27         INVERSE_WINDING (2),
    28         /**
    29          * Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
    30          */
    31         INVERSE_EVEN_ODD(3);
    32 
    33         FillType(int ni) {
    34             nativeInt = ni;
    35         }
    36 
    37         final int nativeInt;
    38     }

    5.3 FillType含义表

    EVEN_ODD 奇偶算法
    INVERSE_EVEN_ODD 反奇偶算法
    WINDING 非零环绕数算法
    INVERSE_WINDING 反非零环绕数算法

    5.4 奇偶算法

    算法:

      从p点向任意方向作一条射线, 若该射线与图形相交的边数为奇数,则p是图形内部点,否则是外部点。

    示例:

    红色的点在多边形内部。从它出发作任意射线(图中画出了两种可能),它与多边形的边必定相交奇数次(图中两条射线分别相交1次和3次)。

    蓝色的点在多边形外部。从它出发作任意射线(图中画出了两种可能),它与多边形的边必定相交偶数次(图中两条射线分别相交0次和2次)。

    5.5 非零环绕数

    算法:该方法常用与判断点是否在多边形或曲线上。
      使多边形的边变为矢量。将环绕数初始化为零。从点p向外做一条射线(可以任意方向),多边形的边从左到右经过射线时环数减1,多边形的边从右往左经过射线时环数加1,最后环数不为0,即表示在多边形内部,反之在外部。

    示例:

    • 5角星上的箭头表示边的方向
    • 从p点向右下作一条射线
    • 环绕数WindingNumber,初始值为0,
    • 从上到下,这里有3条边与射线相交。
    • 第1条边方向是 -->,WindingNumber -= 1
    • 第2条边方向是 <--,WindingNumber += 1
    • 第3条边方向是 <--,WindingNumber += 1
    • 最终WindingNumber = 1,值非0,则在图形内。

    6.路径之间的运算(求交集、并集等)

    6.1 Path.op(xxx)

    源码:与其它path进行运算。它还有一个重载版本。

     1     /**
     2      * Set this path to the result of applying the Op to the two specified paths.
     3      * The resulting path will be constructed from non-overlapping contours.
     4      * The curve order is reduced where possible so that cubics may be turned
     5      * into quadratics, and quadratics maybe turned into lines.
     6      *
     7      * @param path1 The first operand (for difference, the minuend)
     8      * @param path2 The second operand (for difference, the subtrahend)
     9      *
    10      * @return True if operation succeeded, false otherwise and this path remains unmodified.
    11      *
    12      * @see Op
    13      * @see #op(Path, android.graphics.Path.Op)
    14      */
    15     public boolean op(Path path1, Path path2, Op op) {
    16         if (nOp(path1.mNativePath, path2.mNativePath, op.ordinal(), this.mNativePath)) {
    17             isSimplePath = false;
    18             rects = null;
    19             return true;
    20         }
    21         return false;
    22     }
    23     /**
    24      * The logical operations that can be performed when combining two paths.
    25      *
    26      * @see #op(Path, android.graphics.Path.Op)
    27      * @see #op(Path, Path, android.graphics.Path.Op)
    28      */
    29     public enum Op {
    30         /**
    31          * Subtract the second path from the first path.
    32          */
    33         DIFFERENCE,
    34         /**
    35          * Intersect the two paths.
    36          */
    37         INTERSECT,
    38         /**
    39          * Union (inclusive-or) the two paths.
    40          */
    41         UNION,
    42         /**
    43          * Exclusive-or the two paths.
    44          */
    45         XOR,
    46         /**
    47          * Subtract the first path from the second path.
    48          */
    49         REVERSE_DIFFERENCE
    50     }

    参数:前两个参数是参与运算的path,第3个参数是路径运算符。

    6.2 路径运算符

    运算符类比集合运算说明示意图
    XOR 异或 求非交集。
    INTERSECT 交集 Path1与Path2相交的部分
    UNION 并集 包含全部Path1和Path2
    DIFFERENCE 差集 Path1中减去Path2后剩下的部分
    REVERSE_DIFFERENCE 差集 Path2中减去Path1后剩下的部分
  • 相关阅读:
    mysql删选某列重复值
    apache伪静态
    nginx的伪静态
    如何对数据库进行优化
    ci的优缺点
    memcache状态说明
    sql中扩展插入语法
    若给个 个人收款的二维码,如何测试?
    安装自动化测试工具selenium
    PHP 线上项目 无法操作
  • 原文地址:https://www.cnblogs.com/mhbs/p/10989529.html
Copyright © 2011-2022 走看看