浅谈 Quartz2D 在开发中的用处(三)

转载自:http://www.tuicool.com/articles/JzQZbqj


图形上下文栈

遵守栈 "先进后出" 的特点,当我们在画一条线时设置了这条线的状态,当再次画第二条线的时候,这时第二条线的状态也会和第一次一样。如下图所示:

想要用最开始的的状态又要重新设置,所以这时用图形上下文栈操作起来要好很多。先发一下效果图,代码和解析后上。效果图如下图所示:

在写画线段的时候要先获取上下文,下面贴的代码块的第二句是将获取的上下文拷贝一份保存到栈中,栈中的 me 和 图形上下文的 me 不再存在关联。

CGContextRef me = UIGraphicsGetCurrentContext(); 
CGContextSaveGState(me); 

在内存的效果图如下所示:

设置第一个线段的状态,线段宽度为5、颜色为绿色、首尾为圆形,并根据设置的两个坐标点将线段渲染出。内存中的效果图就是将线段的状态保存到图形上下文的 me 中,与栈中的 me 无关。代码如下:

// 设置线段状态
CGContextSetLineWidth(me,5); 
[[UIColor greenColor]set]; 
CGContextSetLineCap(me,kCGLineCapRound);

//  设置线段位置
CGContextMoveToPoint(me, 50, 50);
CGContextAddLineToPoint(me, 100, 100);
CGContextStrokePath(me);

当过掉当前代码块中第一句的代码时,将栈中保存的 me 出栈,来替换当前图形上下文中的 me,也可以理解成清空或赋值,设置第二条线的位置并渲染,最终两条线的结果如图中 View 框中所示。

CGContextRestoreGState(me); 
CGContextMoveToPoint(me, 10, 100);
CGContextAddLineToPoint(me, 150, 150); 
CGContextStrokePath(me);

内存中的效果图如下:

裁剪

将图片在制定反范围内,裁剪出相应的尺寸大小。

用图形来模拟一下效果如下图所示:

代码:

CGContextRef me = UIGraphicsGetCurrentContext(); // 获取上下文    
CGContextAddEllipseInRect(me, CGRectMake(50, 50, 100, 100)); // 画园    
CGContextClip(me); //  裁剪   
CGContextFillPath(me); // 渲染    
UIImage *meImage = [UIImage imageNamed:@"meImage"]; // 定义并初始化
[meImage drawAtPoint:CGPointMake(50, 50)]; // 展示的位置

原图和裁剪后的效果图如下所示:

重绘(刷帧)

- (void)drawRect:(CGRect)rect 方法只能系统调用一次,手动不能调用,所以想要重新在绘制图形就需要在进行系统的调用,需要调用系统的 [self setNeedsDisplay]; 方法来实现。

新建一个圆类,设置圆属性半径 radius ,并且在 - (void)drawRect: 方法中画一个圆,根据半径 self.radius 的值来改变圆的大小。代码如下:

@property(nonatomic,assign) CGFloat radius; // 圆的半径

- (void)drawRect:(CGRect)rect
{
    CGContextRef arc = UIGraphicsGetCurrentContext();
    CGContextAddArc(arc, 100, 100, self.radius, 0, M_PI * 2, 0); 
    [[UIColor orangeColor]set];  
    CGContextFillPath(arc);
}

将图中蓝色的 View 拖到 控制器中,代码如下:

@property (weak, nonatomic) IBOutlet SZXdraw *circleView;

并且将图中滑块进行监听,通过滑动滑块获取的值,来赋值给圆的半径,从而来进行重绘。 代码和示意图如下:

- (IBAction)Slide:(UISlider *)sender
{
    self.circleView.radius = sender.value;
}

通过重写半径的set方法给予赋值和重绘,代码如下:

-(void)setRadius:(CGFloat)radius
{
    _radius = radius;
    [self setNeedsDisplay];
}

来看一下最终的效果动态图:

刷帧多用于做动画特效,下面也是一个简单的小例子,设置一个下落的Y值属性 catY 用来累计下落的大小。通过在 - (void)drawRect 方法中设置动画,在根据 View 的尺寸来判断猫头是否越界,如果越界从头开始。

- (void)drawRect:(CGRect)rect
{
    self.catY += 1;
    if (self.catY >= rect.size.height)
    {
        self.catY = -50;
    }
    UIImage *me = [UIImage imageNamed:@"me"];
    [me drawAtPoint:CGPointMake(0, self.catY)];
}

- (void)awakeFromNib 系统方法中写,CADisplayLink刷帧,每秒刷新60次,此时调用 setNeedsDisplay 系统方法,将 link 加入到消息循环中。

- (void)awakeFromNib
{
    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)];
    [link addToRunLoop:[NSRunLoop mainRunLoop]forMode:NSDefaultRunLoopMode];
}

效果示意图:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值