zoukankan      html  css  js  c++  java
  • iOS 绘画学习(5)


    阴影

    为了给绘制添加阴影,可以在绘制之前,给上下文一个阴影值。阴影的位置用CGSize表示,CGSize里的两个正数表示向下和向右方向。这个模糊值是一个可以无穷大的正数。苹果没有解析这个拉伸是如何工作的,不过经验显示,12是一个刚好的值,99就会显得太锐利。下面是我们在绘制之前,添加的代码:

    con = UIGraphicsGetCurrentContext();
    CGContextSetShadow(con, CGSizeMake(7, 7), 12);
    [self.arrow drawAtPoint:CGPointMake(0,0)]; // ... and so on
    

    但是这样效果好像不是很明显,而且我们每次绘制箭头都会让阴影重叠。我们希望有一个阴影作用于所有的箭头,为了达到这个目的,我们可以使用一个透明图层,基本上算是一个子上下文:

    CGContextRef con = UIGraphicsGetCurrentContext();
    CGContextSetShadow(con, CGSizeMake(7, 7), 12);
    CGContextBeginTransparencyLayer(con, nil);
    [self.arrow drawAtPoint:CGPointMake(0,0)];
    for (int i=0; i<3; i++) {
        CGContextTranslateCTM(con, 20, 100);
        CGContextRotateCTM(con, 30 * M_PI/180.0);
        CGContextTranslateCTM(con, -20, -100);
        [self.arrow drawAtPoint:CGPointMake(0,0)];
    }
    CGContextEndTransparencyLayer(con);
    

    擦除

    函数CGContextClearRect 会清除矩形区域里所有已存在的绘制。结合剪切,它能清除任何形状的区域。

    CGContextClearRect 的行为根据上下文是否是透明而有所不同。在绘制图像时,如何图像上下文是透明的--UIGraphicsBeginImageContextWithOptions 第二个参数是NO --CGContextClearRect 会清除为透明的,否则就会清除为黑色。

    当在一个视图view中直接绘制时(例如drawRect: 或者 drawLayer:inContext:),如果视图的背景颜色是nil或者是一种含有哪怕一点透明的颜色,CGContextClearRect的结果都是透明的。如果背景颜色是完全不透明的,那么CGContextClearRect的结果将是黑色。这是因为视图背景颜色决定了这个视图上下文是透明的,还是不透明的。

    上图的绘制是完全一样的,除了背景颜色一个是完全不透明蓝色,一个是不透明度是0.99的蓝色。我们用CGContextClearRect 清除掉左上角的正方形。 这个视图的drawRect:看上去像下面那样:

    CGContextRef con = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor);
    CGContextFillRect(con, rect);
    CGContextClearRect(con, CGRectMake(0,0,30,30));
    

    点和像素

    点是描述一个在x轴和y轴方向上无维的位置。当我们在图形上下文中绘制时,指定了在哪里绘制,这个位置是与设备分辨率无关的。因为Core Graphics使用CTM和抗锯齿来对应你的绘制在实际的设备输出上。

    但是像素是存在的。一个像素是真实世界中一个实际的,数字化的显示单元。。我们有时候会看到有人建议把线的位置放在0.5的位置上,来把这条线的像素居中,这个建议可能会有用,但是把情况简单化了。UIView有一个contentScaleFactor参数,这个值不是1.0,就是2.0。你可以通过这个参数把像素转换成点。考虑到我们大多数情况是填充一个矩形,而不是描边一个路径。所以下面的代码可以在任意设备上都绘制一条完美的1像素宽的垂直线。

    CGContextFillRect(con, CGRectMake(100,0,1.0/self.contentScaleFactor,100));
    

    内容模式

    一个视图会在它本身还绘制一些其他的东西,和仅仅有背景颜色和子视图不同,它是有内容的。这意味着当重新调整大小时它的 contentMode 属性变得非常重要。正如我前面说到的,绘画系统总是避免要求一个视图重新绘制自己,而是使用之前绘画操作缓存的结果(图像后备存储)。所以,如果一个视图被重新调整大小,系统可能只是简单的根据你的contentMode属性来拉伸,收缩或者重新定位缓存中的绘画。

    下面我沿用之前的代码绘制箭头,子类化一个view,然后在drawRect:中绘制箭头,只是在延时一段时间后把这个view 的高度变成原来的两倍,得到下面的结果:

    void (^resize) (void) = ^{
        CGRect f = mv.bounds; // mv is the MyView instance
        f.size.height *= 2;
        mv.bounds = f;
    };
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), resize);
    

    但是很快,drawRect:这个方法还是会调用,这样我们的绘制就会被重新刷新。由于我们的代码中并没有指定箭头的高度与视图的bounds 的高度有关,所以箭头会变成原来的大小,而不是被拉伸的箭头。

    由于我们的drawRect:方法中指定的箭头的大小和位置与视图的bounds的原点有关,就是左上角,因此我们可以设置视图的contentMode属性为UIViewContentModeTopLeft.还有,我们可以设置contentMode属性为UIViewContentModeRedraw,这样自动拉伸和收缩就是关闭,当视图被重新调整大小,它的setNeedsDisplay 方法会被调用,接着触发drawRect:来重新绘制内容。

  • 相关阅读:
    WampServer Mysql配置
    Java实现 蓝桥杯VIP 算法提高 陶陶摘苹果2
    Java实现 蓝桥杯VIP 算法提高 陶陶摘苹果2
    Java实现 蓝桥杯VIP 算法提高 陶陶摘苹果2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 前10名
  • 原文地址:https://www.cnblogs.com/YungMing/p/4008219.html
Copyright © 2011-2022 走看看