SLDrawView.m 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. //
  2. // SLDrawView.m
  3. // DarkMode
  4. //
  5. // Created by wsl on 2019/10/12.
  6. // Copyright © 2019 wsl. All rights reserved.
  7. //
  8. #import "SLDrawView.h"
  9. @interface SLDrawBezierPath : UIBezierPath
  10. @property (nonatomic, strong) UIColor *color; //曲线颜色
  11. @end
  12. @implementation SLDrawBezierPath
  13. @end
  14. @interface SLDrawView ()
  15. {
  16. BOOL _isWork;
  17. BOOL _isBegan;
  18. }
  19. /// 笔画
  20. @property (nonatomic, strong) NSMutableArray <SLDrawBezierPath *>*lineArray;
  21. /// 图层
  22. @property (nonatomic, strong) NSMutableArray <CAShapeLayer *>*layerArray;
  23. /// 删除的笔画
  24. @property (nonatomic, strong) NSMutableArray <SLDrawBezierPath *>*deleteLineArray;
  25. /// 删除的图层
  26. @property (nonatomic, strong) NSMutableArray <CAShapeLayer *>*deleteLayerArray;
  27. @end
  28. @implementation SLDrawView
  29. #pragma mark - Override
  30. - (instancetype)initWithFrame:(CGRect)frame {
  31. self = [super initWithFrame:frame];
  32. if (self) {
  33. _lineWidth = 5.f;
  34. _lineColor = [UIColor blackColor];
  35. _layerArray = [NSMutableArray array];
  36. _lineArray = [NSMutableArray array];
  37. _deleteLineArray = [NSMutableArray array];
  38. _deleteLayerArray = [NSMutableArray array];
  39. self.backgroundColor = [UIColor whiteColor];
  40. self.clipsToBounds = YES;
  41. self.exclusiveTouch = YES;
  42. }
  43. return self;
  44. }
  45. //开始绘画
  46. - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  47. if ([event allTouches].count == 1) {
  48. _isWork = NO;
  49. _isBegan = YES;
  50. //1、每次触摸的时候都应该去创建一条贝塞尔曲线
  51. SLDrawBezierPath *path = [SLDrawBezierPath new];
  52. //2、移动画笔
  53. UITouch *touch = [touches anyObject];
  54. CGPoint point = [touch locationInView:self];
  55. //设置线宽
  56. path.lineWidth = self.lineWidth;
  57. path.lineCapStyle = kCGLineCapRound; //线条拐角
  58. path.lineJoinStyle = kCGLineJoinRound; //终点处理
  59. [path moveToPoint:point];
  60. //设置颜色
  61. path.color = self.lineColor;//保存线条当前颜色
  62. [self.lineArray addObject:path];
  63. CAShapeLayer *slayer = [self createShapeLayer:path];
  64. [self.layer addSublayer:slayer];
  65. [self.layerArray addObject:slayer];
  66. }
  67. [super touchesBegan:touches withEvent:event];
  68. }
  69. //绘画中
  70. - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  71. if (_isBegan || _isWork) {
  72. UITouch *touch = [touches anyObject];
  73. CGPoint point = [touch locationInView:self];
  74. SLDrawBezierPath *path = self.lineArray.lastObject;
  75. if (!CGPointEqualToPoint(path.currentPoint, point)) {
  76. if (_isBegan && self.drawBegan) self.drawBegan();
  77. _isBegan = NO;
  78. _isWork = YES;
  79. [path addLineToPoint:point];
  80. CAShapeLayer *slayer = self.layerArray.lastObject;
  81. slayer.path = path.CGPath;
  82. }
  83. }
  84. [super touchesMoved:touches withEvent:event];
  85. }
  86. //结束绘画
  87. - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
  88. if (_isWork) {
  89. if (self.drawEnded) self.drawEnded();
  90. } else {
  91. if ((_isBegan)) {
  92. [self goBack];
  93. }
  94. }
  95. _isBegan = NO;
  96. _isWork = NO;
  97. [super touchesEnded:touches withEvent:event];
  98. }
  99. //取消绘画
  100. - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  101. if (_isWork) {
  102. if (self.drawEnded) self.drawEnded();
  103. } else {
  104. if ((_isBegan)) {
  105. [self goBack];
  106. }
  107. }
  108. _isBegan = NO;
  109. _isWork = NO;
  110. [super touchesCancelled:touches withEvent:event];
  111. }
  112. #pragma mark - Help Methods
  113. //创建线条图层
  114. - (CAShapeLayer *)createShapeLayer:(SLDrawBezierPath *)path {
  115. /** 1、渲染快速。CAShapeLayer使用了硬件加速,绘制同一图形会比用Core Graphics快很多。Core Graphics实现示例: https://github.com/wsl2ls/Draw.git
  116. 2、高效使用内存。一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。
  117. 3、不会被图层边界剪裁掉。
  118. 4、不会出现像素化。 */
  119. CAShapeLayer *slayer = [CAShapeLayer layer];
  120. slayer.path = path.CGPath;
  121. slayer.backgroundColor = [UIColor clearColor].CGColor;
  122. slayer.fillColor = [UIColor clearColor].CGColor;
  123. slayer.lineCap = kCALineCapRound;
  124. slayer.lineJoin = kCALineJoinRound;
  125. slayer.strokeColor = path.color.CGColor;
  126. slayer.lineWidth = path.lineWidth;
  127. return slayer;
  128. }
  129. #pragma mark - Getter
  130. - (BOOL)isDrawing {
  131. return _isWork;
  132. }
  133. - (BOOL)canForward {
  134. return self.deleteLineArray.count;
  135. }
  136. - (BOOL)canBack {
  137. return self.lineArray.count;
  138. }
  139. #pragma mark - Event Handle
  140. //前进
  141. - (void)goForward {
  142. if ([self canForward]) {
  143. //添加刚删除的线条
  144. [self.layer addSublayer:self.deleteLayerArray.lastObject];
  145. [self.lineArray addObject:self.deleteLineArray.lastObject];
  146. [self.layerArray addObject:self.deleteLayerArray.lastObject];
  147. //从删除池中除去
  148. [self.deleteLayerArray removeLastObject];
  149. [self.deleteLineArray removeLastObject];
  150. }
  151. }
  152. //返回
  153. - (void)goBack {
  154. if ([self canBack]) {
  155. //保存上一步删除的线条
  156. [self.deleteLineArray addObject:self.lineArray.lastObject];
  157. [self.deleteLayerArray addObject:self.layerArray.lastObject];
  158. //删除上一步
  159. [self.layerArray.lastObject removeFromSuperlayer];
  160. [self.layerArray removeLastObject];
  161. [self.lineArray removeLastObject];
  162. }
  163. }
  164. - (void)clear {
  165. [self.layerArray removeAllObjects];
  166. [self.lineArray removeAllObjects];
  167. [self.deleteLayerArray removeAllObjects];
  168. [self.deleteLineArray removeAllObjects];
  169. [self.layer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
  170. }
  171. #pragma mark - 数据
  172. - (NSDictionary *)data {
  173. if (self.lineArray.count) {
  174. return @{@"kSLDrawViewData":[self.lineArray copy]};
  175. }
  176. return nil;
  177. }
  178. - (void)setData:(NSDictionary *)data {
  179. NSArray *lineArray = data[@"kSLDrawViewData"];
  180. if (lineArray.count) {
  181. for (SLDrawBezierPath *path in lineArray) {
  182. CAShapeLayer *slayer = [self createShapeLayer:path];
  183. [self.layer addSublayer:slayer];
  184. [self.layerArray addObject:slayer];
  185. }
  186. [self.lineArray addObjectsFromArray:lineArray];
  187. }
  188. }
  189. @end