zoukankan      html  css  js  c++  java
  • iOS 2D绘图详解(Quartz 2D)之路径(stroke,fill,clip,subpath,blend)

    Stroke-描边

    影响描边的因素

    • 线的宽度-CGContextSetLineWidth
    • 交叉线的处理方式-CGContextSetLineJoin
    • 线顶端的处理方式-CGContextSetLineCap
    • 进一步限制交叉线的处理方式 -CGContextSetMiterLimit
    • 是否要虚线-Line dash pattern
    • 颜色控件-CGContextSetStrokeColorSpace
    • 画笔颜色-CGContextSetStrokeColor/CGContextSetStrokeColorWithColor
    • 描边模式-CGContextSetStrokePattern

    虚线,画笔颜色,交叉的处理方式,顶端的处理方式,线宽度在之前这篇文章里有讲过,这里不再赘述。

    CGContextSetMiterLimit

    如果当前交叉线绘图模式是kCGLineJoinMiter( CGContextSetLineJoin),quartz根据设置的miter值来判断线的join是bevel或者miter。具体的模式是:将miter的长度除以线的宽度,如果小于设置的mitetLimit值,则join style为bevel;

    先看看三种join效果

    举个例子就懂了

        CGContextMoveToPoint(context,10,10);
        CGContextAddLineToPoint(context, 50, 50);
        CGContextAddLineToPoint(context, 10, 90);
        CGContextSetLineWidth(context, 10.0);
        CGContextSetLineJoin(context, kCGLineJoinMiter);
        CGContextSetMiterLimit(context,20.0);
        CGContextStrokePath(context);

    效果

    将Miter设置为1,则效果如下

    CGContextSetStrokeColorSpace和pattern会在以后的文章详细阐述,这里暂时先略去


    Fill-填充

    Quartz填充的时候会认为subpath是封闭的,然后根据规则来填充。有两种规则:

    nonzero winding number rule.沿着当前点,画一条直线到区域外,检查交叉点,如果交叉点从左到右,则加一,从右到左,则减去一。如果结果不为0,则绘制。参见这个link

    even-odd rule,沿着当前点,花一条线到区域外,然后检查相交的路径,偶数则绘制,奇数则不绘制。
    具体效果如下
    这里写图片描述

    相关函数

    • CGContextEOFillPath - 用even-odd rule来填充
    • CGContextFillPath - 用nonzero winding number rule方式填充
    • CGContextFillRect/CGContextFillRects - 填充指定矩形区域内path
    • CGContextFillEllipseInRect - 填充椭圆
    • CGContextDrawPath - 绘制当前path(根据参数stroke/fill)

    Clip-切割

    顾名思义,根据path只绘制指定的区域,在区域外的都不会绘制。
    举个例子,截取圆形区域
    效果

    注意,切割是和状态相关的,以为这切割以后都是在切割后context中绘制的。
    如果要保存状态,参照这篇文章里讲的压栈和出栈

     - (void)drawRect:(CGRect)rect {
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextBeginPath (context);
        CGContextAddArc(context,50, 50,20,0, M_PI * 2,true);
        CGContextClosePath (context);
        CGContextClip (context);
        CGContextSetFillColorWithColor(context, [UIColor lightGrayColor].CGColor);
        CGContextFillRect(context, rect);
    
        //New Code
        CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
    
        CGContextMoveToPoint(context,10,10);
        CGContextAddLineToPoint(context, 50, 50);
        CGContextAddLineToPoint(context, 10, 90);
    
        CGContextSetLineWidth(context, 10.0);
        CGContextSetLineJoin(context, kCGLineJoinMiter);
        CGContextSetMiterLimit(context,20.0);
        CGContextStrokePath(context);
    }
    -(instancetype)initWithFrame:(CGRect)frame{
        if (self = [super initWithFrame:frame]) {
            self.opaque = NO;
        }
        return self;
    }

    相关函数

    • CGContextClip 按照nonzero winding number rule规则切割
    • CGContextEOClip 按照even-odd规则切割
    • CGContextClipToRect 切割到指定矩形
    • CGContextClipToRects 切割到指定矩形组
    • CGContextClipToMask 切割到mask

    Subpath - 子路径

    很简单,在stroke/fill或者CGContextBeginPath/CGContextClosePath以后就新开启一个子路径。

    注意:

    CGContextClosePath,会连接第一个点和最后一个点


    Blend-混合模式

    Quartz中,默认的颜色混合模式采用如下公式
    result = (alpha * foreground) + (1 - alpha) * background

    可以使用CGContextSetBlendMode来设置不同的颜色混合模式,注意设置blend是与context绘制状态相关的,一切与状态相关的设置都要想到状态堆栈(如果看不懂这句,看我之前的那两篇文章里讲的)。

    先看看官方文档里的例子,最后我会写个自己的例子
    background

    foreGround


    Normal Blend Mode

    效果


    Multiply Blend Mode

    交叉部分会显得比较暗,用上一层和底层相乘,至少和一层一样暗


    Screen Blend Mode

    交叉部分比较亮,上层的reverse和下层的reverse相乘,至少和一个一样亮


    blend模式较多,这里不一一列举了,参见官方文档

  • 相关阅读:
    HDU 1584 蜘蛛牌(DFS)
    HDU 1800 Flying to the Mars(贪心)
    zsh: command not found: java (xxx)
    Deepin20安装Mysql8
    Deepin全局菜单
    Ubuntu PPA 解读
    Node安装与配置
    Windows安装配置Maven
    idea 安装 Vue 插件没有Vue component选项
    Linux桌面系统创建应用程序快捷方式
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/5948971.html
Copyright © 2011-2022 走看看