普通版本完成的锯齿很严重 但是Ios系统中仅CGContextClearRect 并不存在cyclo等方法。 网上查了一些资料。 发现还是利用到了CG 中的Mask来实现效果图:
这种效果可以自定义画笔的粗细等相关设置,不会像普通模式中出现比较严重的锯齿。具体分析如下: 1.获取需要隐藏View的layer的CGImageRef用于后面配合掩码 2.开辟符合1的CGImageRef的CFMutableDataRef空间 给下面的掩码BitmapContext使用 3.通过CFMutableDataRef获得CGDataProviderRef (maskCreate用到) 3.BitmapContextCreate 4.BitmapContext填充黑色 并且设置画笔相关(白色,宽度,线帽(cap)) 5.CGImageMaskCreate 将CGDataProviderRef 传入 则得到CGImageRef指向的是刚才创建BitmapContext。改变BitmapContext 则此CGImageRef内容也会改变 6.CGImageCreateWithMask - 通过Mask的CGImageRef创建CGImageRef 此CGImageRef随 Maskde CGImageRef变化(所以 BitmapContext改变 Mask改变 mask掩码后的CGImageRef改变) 7.释放 8.手指触摸时,根据上一个CGPoint 和此次的CGPoint 给bitmapContext新增path 并且绘制。然后调用【self setNeedsDisplay】,在重绘中(-drawRect) 重新获取通过mask后的CGImageRef 获取最新的UIImage 9.将最新的UIImage drawRect到界面代码://// PLLScrathView.h// PLLScratchViewDemo//// Created by liu poolo on 14-7-31.// Copyright (c) 2014年 liu poolo. All rights reserved.//#import <UIKit/UIKit.h>#import <QuartzCore/QuartzCore.h>@interface PLLScratchView : UIView@property (nonatomic,assign) float sizeBrush;-(void)setHideView:(UIView*) hideView;@end//// PLLScrathView.m// PLLScratchViewDemo//// Created by liu poolo on 14-7-31.// Copyright (c) 2014年 liu poolo. All rights reserved.//#import "PLLScratchView.h"@interface PLLScratchView(){ CGContextRef _contextMask;//maskContext 用户touch 改变的context CGImageRef _scratchCGImg;//CGimageRef 封装_contextMask 图片信息 _contextMask改变 跟着改变 直到 调用生成UIImage CGPoint currPonit; CGPoint prePoint;}@end@implementation PLLScratchView@synthesize sizeBrush;- (id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { [self setOpaque:NO]; //设置透明 如果不透明就没法看到下一层了 self.sizeBrush=10.0f; } return self;}- (void)drawRect:(CGRect)rect{ [super drawRect:rect]; UIImage* imageToDraw=[UIImage imageWithCGImage:_scratchCGImg]; [imageToDraw drawInRect:self.frame];}//setSizeBrush before setHideView-(void)setHideView:(UIView*) hideView{ CGColorSpaceRef colorSpace=CGColorSpaceCreateDeviceGray(); CGFloat scale = [UIScreen mainScreen].scale; //获得当前传入View的CGImage UIGraphicsBeginImageContextWithOptions(hideView.bounds.size, NO, 0); hideView.layer.contentsScale=scale; [hideView.layer renderInContext:UIGraphicsGetCurrentContext()]; CGImageRef hideCGImg=UIGraphicsGetImageFromCurrentImageContext().CGImage; UIGraphicsEndImageContext(); //绘制Bitmap掩码 size_t width=CGImageGetWidth(hideCGImg); size_t height=CGImageGetHeight(hideCGImg); CFMutableDataRef pixels; pixels=CFDataCreateMutable(NULL, width*height); //创建一个可变的dataRef 用于bitmap存储记录 _contextMask = CGBitmapContextCreate(CFDataGetMutableBytePtr(pixels), width, height , 8, width, colorSpace, kCGImageAlphaNone); //数据提供者 CGDataProviderRef dataProvider=CGDataProviderCreateWithCFData(pixels); //填充黑色背景 mask中黑色范围为显示内容 白色为不显示 CGContextSetFillColorWithColor(_contextMask, [UIColor blackColor].CGColor); CGContextFillRect(_contextMask, self.frame); CGContextSetStrokeColorWithColor(_contextMask, [UIColor whiteColor].CGColor); CGContextSetLineWidth(_contextMask, self.sizeBrush); CGContextSetLineCap(_contextMask, kCGLineCapRound); CGImageRef mask=CGImageMaskCreate(width, height, 8, 8, width, dataProvider, nil, NO); _scratchCGImg=CGImageCreateWithMask(hideCGImg, mask); CGImageRelease(mask); CGColorSpaceRelease(colorSpace); }-(void)scratchViewFrom:(CGPoint)startPoint toEnd:(CGPoint)endPoint{ float scale=[UIScreen mainScreen].scale; //CG的Y与UI的是反的 UI的y0在左上角 CG在左下 CGContextMoveToPoint(_contextMask, startPoint.x*scale, (self.frame.size.height-startPoint.y)*scale); CGContextAddLineToPoint(_contextMask, endPoint.x*scale,(self.frame.size.height-endPoint.y)*scale); CGContextStrokePath(_contextMask); [self setNeedsDisplay];}-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ [super touchesBegan:touches withEvent:event];}-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ [super touchesMoved:touches withEvent:event]; UITouch *touch=[touches anyObject]; currPonit=[touch locationInView:self]; prePoint=[touch previousLocationInView:self]; [self scratchViewFrom:prePoint toEnd:currPonit];}-(void)toucheseEnd:(NSSet *)touches withEvent:(UIEvent *)event{ [super touchesEnded:touches withEvent:event]; UITouch *touch=[touches anyObject]; currPonit=[touch locationInView:self]; prePoint=[touch previousLocationInView:self]; [self scratchViewFrom:prePoint toEnd:currPonit];}-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{ [super touchesCancelled:touches withEvent:event];}@end