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:来重新绘制内容。

  • 相关阅读:
    aspx页面按钮写返回上一页代码
    Javascript呼叫.axd文档
    获取GridView TemplateField的数据
    对象失去焦点时自己动提交数据 V2
    从图片路径获取图片尺寸
    双击一个图片然后跳转到另一个页面去
    Javascript alert消息换行
    ASP.NET播放Flash(.SWF)视频
    绑定List<T>到asp:Table控件
    Linux系统下的多线程编程条件变量&信号量
  • 原文地址:https://www.cnblogs.com/YungMing/p/4008219.html
Copyright © 2011-2022 走看看