普通版本完成的鋸齒很嚴重 但是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
- 大小: 566.6 KB