畫(huà)板(涂鴉)實(shí)現(xiàn)
2017.3.7更新
- 不使用
drawRect
- 內(nèi)存消耗低 (把demo中XIB刪除掉,內(nèi)存大概在15M左右)
//橡皮擦
- (void)setEraseBrush:(HBPath *)path{
UIGraphicsBeginImageContextWithOptions(self.frame.size, false, 0);
[self.drawImage.image drawInRect:self.bounds];
[[UIColor clearColor] set];
path.bezierPath.lineWidth = _lineWidth;
[path.bezierPath strokeWithBlendMode:kCGBlendModeClear alpha:1.0];
[path.bezierPath stroke];
self.drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
需求
- 更換
畫(huà)布背景
(獲取 拍照 或者 相冊(cè) 的圖像) - 具有
拍照
截屏
保存功能 - 不同的
畫(huà)筆顏色刃跛,線寬
- 具有
撤銷(xiāo)
返回
清屏
擦除
功能
思路
主要分三大塊
- 背景
- 畫(huà)布
- 畫(huà)筆的功能界面
1.首先獲取用戶觸摸事件開(kāi)始
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint point = [self getTouchSet:touches];
HBPath *path = [HBPath pathToPoint:point pathWidth:_lineWidth isEraser:self.ise];
path.pathColor = _lineColor;
path.imagePath = [NSString stringWithFormat:@"%@.png",[self getTimeString]];
[self.paths addObject:path];
[self.tempPoints addObject:[HBDrawPoint drawPoint:point]];
if ([self.delegate respondsToSelector:@selector(drawBoard:drawingStatus:model:)]) {
[self.delegate drawBoard:self drawingStatus:HBDrawingStatusBegin model:nil];
}
}
HBPath
封裝的NSObject
對(duì)象
paths
:裝有HBPath
對(duì)象
#pragma mark - HBPath
@interface HBPath : NSObject
@property (nonatomic, strong) UIColor *pathColor;//畫(huà)筆顏色
@property (nonatomic, assign) CGFloat lineWidth;//線寬
@property (nonatomic, assign) BOOL isEraser;//橡皮擦
@property (nonatomic, assign) HBDrawingShapeType shapType;//繪制樣式
@property (nonatomic, copy) NSString *imagePath;//圖片路徑
@property (nonatomic, strong) UIBezierPath *bezierPath;
+ (instancetype)pathToPoint:(CGPoint)beginPoint pathWidth:(CGFloat)pathWidth isEraser:(BOOL)isEraser;//初始化對(duì)象
- (void)pathLineToPoint:(CGPoint)movePoint WithType:(HBDrawingShapeType)shapeType;//畫(huà)
@end
2.移動(dòng)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint point = [self getTouchSet:touches];
HBPath *path = [self.paths lastObject];
[path pathLineToPoint:point WithType:self.shapType];
if (self.ise) {
[self setEraseBrush:path];
}else{
[self.drawView setBrush:path];
}
[self.tempPoints addObject:[HBDrawPoint drawPoint:point]];
if ([self.delegate respondsToSelector:@selector(drawBoard:drawingStatus:model:)]) {
[self.delegate drawBoard:self drawingStatus:HBDrawingStatusMove model:nil];
}
}
3.結(jié)束
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesMoved:touches withEvent:event];
HBPath *path = [self.paths lastObject];
UIImage *image = [self screenshot:self.drawImage];
self.drawImage.image = image;
[self.drawView setBrush:nil];
NSData *imageData = UIImagePNGRepresentation(image);//UIImageJPEGRepresentation(image, 0.4);
NSString *filePath = [ThumbnailPath stringByAppendingPathComponent:path.imagePath];
BOOL isSave = [NSFileManager hb_saveData:imageData filePath:filePath];
if (isSave) {
NSLog(@"%@", [NSString stringWithFormat:@"保存成功: %@",filePath]);
}
HBDrawModel *model = [[HBDrawModel alloc] init];
model.paintColor = [_lineColor toColorString];
model.paintSize = @(_lineWidth);
model.isEraser = [NSNumber numberWithBool:path.isEraser];
model.pointList = self.tempPoints;
model.shapType = [NSNumber numberWithInteger:self.shapType];
if ([self.delegate respondsToSelector:@selector(drawBoard:drawingStatus:model:)]) {
[self.delegate drawBoard:self drawingStatus:HBDrawingStatusEnd model:model];
}
//清空
[self.tempPoints removeAllObjects];
}
其中
HBDrawModel
對(duì)象的作用是:操作結(jié)束后傳遞給外界操作的參數(shù)
擁有以下屬性:
/**所有點(diǎn)的集合***/
@property (nonatomic, strong) NSArray * pointList;
/**畫(huà)筆的顏色***/
@property (nonatomic, copy) NSString * paintColor;
/**背景圖片***/
@property (nonatomic, copy) NSString * background;
/**動(dòng)作 (返回 前進(jìn) 畫(huà) 改變背景 清屏)默認(rèn)是 Action_playing ***/
@property (nonatomic, copy) NSString * action;
/**畫(huà)筆大小***/
@property (nonatomic, strong) NSNumber * paintSize;
/**設(shè)備分辨率 寬***/
@property (nonatomic, strong) NSNumber * width;
/**設(shè)備分辨率 高***/
@property (nonatomic, strong) NSNumber * hight;
/**是不是橡皮擦***/
@property (nonatomic, strong) NSNumber * isEraser;
4.繪制
- (void)setBrush:(HBPath *)path
{
CAShapeLayer *shapeLayer = (CAShapeLayer *)self.layer;
shapeLayer.strokeColor = path.pathColor.CGColor;
shapeLayer.fillColor = [UIColor clearColor].CGColor;
shapeLayer.lineJoin = kCALineJoinRound;
shapeLayer.lineCap = kCALineCapRound;
shapeLayer.lineWidth = path.bezierPath.lineWidth;
((CAShapeLayer *)self.layer).path = path.bezierPath.CGPath;
}
最后強(qiáng)調(diào)一下關(guān)于橡皮擦的注意點(diǎn)挪捕!
和繪制線是一樣的诚卸,區(qū)別在于繪制的時(shí)候加上下面這句代碼。
if (self.isEraser)
[self.bezierPath strokeWithBlendMode:kCGBlendModeClear alpha:1.0];
更新->在最上面
真正的擦除你已經(jīng)畫(huà)的線,跟你畫(huà)布的背景是不是白色纽什,或者其他顏色
沒(méi)有關(guān)系措嵌!如果你的背景是圖片躲叼,設(shè)置畫(huà)筆的顏色與畫(huà)布的顏色一致,就不會(huì)奏效了企巢。
當(dāng)然除了上面是使用貝塞爾路徑
繪制以外枫慷,你也可以使用上下文去實(shí)現(xiàn),找準(zhǔn)這個(gè)屬性浪规。媽媽再也不用擔(dān)心橡皮擦啦~~~
問(wèn)題
當(dāng)兩個(gè)設(shè)備中或听,一端正在畫(huà),另一端繪制對(duì)方畫(huà)的線笋婿。如果對(duì)方先慢畫(huà)誉裆,后快畫(huà)。怎么在另一端也繪制出這種速度感缸濒?足丢?
如您知道的話,希望在評(píng)論中可以給我一些思路庇配。
解決
在這里感謝 @柯拉Sir @夢(mèng)的森林 提供的思路斩跌。最新的代碼已經(jīng)更新,需要的朋友自取哈捞慌。
如果這個(gè)文章幫到了你耀鸦,一定給我
Star
哦!
GitHub 歡迎圍觀Pピ琛袖订!