画板(涂鸦)实现
设置面板.png
背景.png
2017.3.7更新
- 不使用
drawRect
- 内存消耗低 (把demo中XIB删除掉,内存大概在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();
}
需求
- 更换
画布背景
(获取 拍照 或者 相册 的图像) - 具有
拍照
截屏
保存功能 - 不同的
画笔颜色,线宽
- 具有
撤销
返回
清屏
擦除
功能
思路
主要分三大块
- 背景
- 画布
- 画笔的功能界面
1.首先获取用户触摸事件开始
- (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
对象
paths
:装有HBPath
对象
#pragma mark - HBPath
@interface HBPath : NSObject
@property (nonatomic, strong) UIColor *pathColor;//画笔颜色
@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;//初始化对象
- (void)pathLineToPoint:(CGPoint)movePoint WithType:(HBDrawingShapeType)shapeType;//画
@end
2.移动
- (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.结束
- (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
对象的作用是:操作结束后传递给外界操作的参数
拥有以下属性:
/**所有点的集合***/
@property (nonatomic, strong) NSArray * pointList;
/**画笔的颜色***/
@property (nonatomic, copy) NSString * paintColor;
/**背景图片***/
@property (nonatomic, copy) NSString * background;
/**动作 (返回 前进 画 改变背景 清屏)默认是 Action_playing ***/
@property (nonatomic, copy) NSString * action;
/**画笔大小***/
@property (nonatomic, strong) NSNumber * paintSize;
/**设备分辨率 宽***/
@property (nonatomic, strong) NSNumber * width;
/**设备分辨率 高***/
@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;
}
最后强调一下关于橡皮擦的注意点!
和绘制线是一样的,区别在于绘制的时候加上下面这句代码。
if (self.isEraser)
[self.bezierPath strokeWithBlendMode:kCGBlendModeClear alpha:1.0];
更新->在最上面
真正的擦除你已经画的线,跟你画布的背景是不是白色,或者其他颜色
没有关系!如果你的背景是图片,设置画笔的颜色与画布的颜色一致,就不会奏效了。
当然除了上面是使用贝塞尔路径
绘制以外,你也可以使用上下文去实现,找准这个属性。妈妈再也不用担心橡皮擦啦~~~
问题
当两个设备中,一端正在画,另一端绘制对方画的线。如果对方先慢画,后快画。怎么在另一端也绘制出这种速度感??
如您知道的话,希望在评论中可以给我一些思路。
解决
在这里感谢 @柯拉Sir @梦的森林 提供的思路。最新的代码已经更新,需要的朋友自取哈。
如果这个文章帮到了你,一定给我
Star
哦!
GitHub 欢迎围观!!
网友评论
这个问题解决的代码在哪呢~~没找着
现在CPU达到90多
1、使用CAShapelayer
2、touchesEnded后,合成layer和图片。
3、画曲线时,更圆滑。
这样减少了cpu的占用,不论画多少笔,都一样,不掉帧。
https://github.com/linsendear/LSDrawTest
这个怎么解决的
我下载了在GitHub上最新的代码,发现一个问题,当在画矩形和圆形时做上下拖动和左右拖动,位置会发生改变!!!
{
CGFloat x = startPoint.x <= endPoint.x ? startPoint.x: endPoint.x;
CGFloat y = startPoint.y <= endPoint.y ? startPoint.y : endPoint.y;
CGFloat width = fabs(startPoint.x - endPoint.x);
CGFloat height = fabs(startPoint.y - endPoint.y);
return CGRectMake(x , y , width, height);
}
修改下这个代码
这是基于路径的绘图 基于像素的绘图 怎么实现