KKCutGridView.m 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. //
  2. // KKCutGridView.m
  3. // WWImageEdit
  4. //
  5. // Created by 邬维 on 2017/1/16.
  6. // Copyright © 2017年 kook. All rights reserved.
  7. //
  8. #import "KKCutGridView.h"
  9. #import "KKCutCircle.h"
  10. #import "KKCutGridLayer.h"
  11. static const NSUInteger kLeftTopCircleView = 1;
  12. static const NSUInteger kLeftBottomCircleView = 2;
  13. static const NSUInteger kRightTopCircleView = 3;
  14. static const NSUInteger kRightBottomCircleView = 4;
  15. @implementation KKCutGridView{
  16. KKCutGridLayer *_gridLayer;
  17. //4个角
  18. KKCutCircle *_ltView;
  19. KKCutCircle *_lbView;
  20. KKCutCircle *_rtView;
  21. KKCutCircle *_rbView;
  22. }
  23. - (id)initWithSuperview:(UIView*)superview frame:(CGRect)frame{
  24. self = [super initWithFrame:frame];
  25. if(self){
  26. [superview addSubview:self];
  27. _gridLayer = [[KKCutGridLayer alloc] init];
  28. _gridLayer.frame = self.bounds;
  29. [self.layer addSublayer:_gridLayer];
  30. _ltView = [self clippingCircleWithTag:kLeftTopCircleView];
  31. _lbView = [self clippingCircleWithTag:kLeftBottomCircleView];
  32. _rtView = [self clippingCircleWithTag:kRightTopCircleView];
  33. _rbView = [self clippingCircleWithTag:kRightBottomCircleView];
  34. UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGridView:)];
  35. [self addGestureRecognizer:panGesture];
  36. self.clippingRect = self.bounds;
  37. }
  38. return self;
  39. }
  40. //4个角的拖动圆球
  41. - (KKCutCircle*)clippingCircleWithTag:(NSInteger)tag
  42. {
  43. KKCutCircle *view = [[KKCutCircle alloc] initWithFrame:CGRectMake(0, 0, 75, 75)];
  44. view.tag = tag;
  45. UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panCircleView:)];
  46. [view addGestureRecognizer:panGesture];
  47. [self.superview addSubview:view];
  48. return view;
  49. }
  50. - (void)removeFromSuperview
  51. {
  52. [super removeFromSuperview];
  53. [_ltView removeFromSuperview];
  54. [_lbView removeFromSuperview];
  55. [_rtView removeFromSuperview];
  56. [_rbView removeFromSuperview];
  57. }
  58. - (void)setBgColor:(UIColor *)bgColor
  59. {
  60. _gridLayer.bgColor = bgColor;
  61. }
  62. - (void)setGridColor:(UIColor *)gridColor
  63. {
  64. _gridLayer.gridColor = gridColor;
  65. }
  66. - (void)setClippingRect:(CGRect)clippingRect
  67. {
  68. _clippingRect = clippingRect;
  69. _ltView.center = [self.superview convertPoint:CGPointMake(_clippingRect.origin.x, _clippingRect.origin.y) fromView:self];
  70. _lbView.center = [self.superview convertPoint:CGPointMake(_clippingRect.origin.x, _clippingRect.origin.y+_clippingRect.size.height) fromView:self];
  71. _rtView.center = [self.superview convertPoint:CGPointMake(_clippingRect.origin.x+_clippingRect.size.width, _clippingRect.origin.y) fromView:self];
  72. _rbView.center = [self.superview convertPoint:CGPointMake(_clippingRect.origin.x+_clippingRect.size.width, _clippingRect.origin.y+_clippingRect.size.height) fromView:self];
  73. _gridLayer.clippingRect = clippingRect;
  74. [self setNeedsDisplay];
  75. }
  76. - (void)setNeedsDisplay
  77. {
  78. [super setNeedsDisplay];
  79. [_gridLayer setNeedsDisplay];
  80. }
  81. //拖动4个角
  82. - (void)panCircleView:(UIPanGestureRecognizer*)sender
  83. {
  84. CGPoint point = [sender locationInView:self];
  85. CGPoint dp = [sender translationInView:self];
  86. CGRect rct = self.clippingRect;
  87. const CGFloat W = self.frame.size.width;
  88. const CGFloat H = self.frame.size.height;
  89. CGFloat minX = 0;
  90. CGFloat minY = 0;
  91. CGFloat maxX = W;
  92. CGFloat maxY = H;
  93. CGFloat ratio = (sender.view.tag == kLeftBottomCircleView || sender.view.tag == kRightTopCircleView) ? -0 : 0;
  94. switch (sender.view.tag) {
  95. case kLeftTopCircleView: // upper left
  96. {
  97. maxX = MAX((rct.origin.x + rct.size.width) - 0.1 * W, 0.1 * W);
  98. maxY = MAX((rct.origin.y + rct.size.height) - 0.1 * H, 0.1 * H);
  99. if(ratio!=0){
  100. CGFloat y0 = rct.origin.y - ratio * rct.origin.x;
  101. CGFloat x0 = -y0 / ratio;
  102. minX = MAX(x0, 0);
  103. minY = MAX(y0, 0);
  104. point.x = MAX(minX, MIN(point.x, maxX));
  105. point.y = MAX(minY, MIN(point.y, maxY));
  106. if(-dp.x*ratio + dp.y > 0){ point.x = (point.y - y0) / ratio; }
  107. else{ point.y = point.x * ratio + y0; }
  108. }
  109. else{
  110. point.x = MAX(minX, MIN(point.x, maxX));
  111. point.y = MAX(minY, MIN(point.y, maxY));
  112. }
  113. rct.size.width = rct.size.width - (point.x - rct.origin.x);
  114. rct.size.height = rct.size.height - (point.y - rct.origin.y);
  115. rct.origin.x = point.x;
  116. rct.origin.y = point.y;
  117. break;
  118. }
  119. case kLeftBottomCircleView: // lower left
  120. {
  121. maxX = MAX((rct.origin.x + rct.size.width) - 0.1 * W, 0.1 * W);
  122. minY = MAX(rct.origin.y + 0.1 * H, 0.1 * H);
  123. if(ratio!=0){
  124. CGFloat y0 = (rct.origin.y + rct.size.height) - ratio* rct.origin.x ;
  125. CGFloat xh = (H - y0) / ratio;
  126. minX = MAX(xh, 0);
  127. maxY = MIN(y0, H);
  128. point.x = MAX(minX, MIN(point.x, maxX));
  129. point.y = MAX(minY, MIN(point.y, maxY));
  130. if(-dp.x*ratio + dp.y < 0){ point.x = (point.y - y0) / ratio; }
  131. else{ point.y = point.x * ratio + y0; }
  132. }
  133. else{
  134. point.x = MAX(minX, MIN(point.x, maxX));
  135. point.y = MAX(minY, MIN(point.y, maxY));
  136. }
  137. rct.size.width = rct.size.width - (point.x - rct.origin.x);
  138. rct.size.height = point.y - rct.origin.y;
  139. rct.origin.x = point.x;
  140. break;
  141. }
  142. case kRightTopCircleView: // upper right
  143. {
  144. minX = MAX(rct.origin.x + 0.1 * W, 0.1 * W);
  145. maxY = MAX((rct.origin.y + rct.size.height) - 0.1 * H, 0.1 * H);
  146. if(ratio!=0){
  147. CGFloat y0 = rct.origin.y - ratio * (rct.origin.x + rct.size.width);
  148. CGFloat yw = ratio * W + y0;
  149. CGFloat x0 = -y0 / ratio;
  150. maxX = MIN(x0, W);
  151. minY = MAX(yw, 0);
  152. point.x = MAX(minX, MIN(point.x, maxX));
  153. point.y = MAX(minY, MIN(point.y, maxY));
  154. if(-dp.x*ratio + dp.y > 0){ point.x = (point.y - y0) / ratio; }
  155. else{ point.y = point.x * ratio + y0; }
  156. }
  157. else{
  158. point.x = MAX(minX, MIN(point.x, maxX));
  159. point.y = MAX(minY, MIN(point.y, maxY));
  160. }
  161. rct.size.width = point.x - rct.origin.x;
  162. rct.size.height = rct.size.height - (point.y - rct.origin.y);
  163. rct.origin.y = point.y;
  164. break;
  165. }
  166. case kRightBottomCircleView: // lower right
  167. {
  168. minX = MAX(rct.origin.x + 0.1 * W, 0.1 * W);
  169. minY = MAX(rct.origin.y + 0.1 * H, 0.1 * H);
  170. if(ratio!=0){
  171. CGFloat y0 = (rct.origin.y + rct.size.height) - ratio * (rct.origin.x + rct.size.width);
  172. CGFloat yw = ratio * W + y0;
  173. CGFloat xh = (H - y0) / ratio;
  174. maxX = MIN(xh, W);
  175. maxY = MIN(yw, H);
  176. point.x = MAX(minX, MIN(point.x, maxX));
  177. point.y = MAX(minY, MIN(point.y, maxY));
  178. if(-dp.x*ratio + dp.y < 0){ point.x = (point.y - y0) / ratio; }
  179. else{ point.y = point.x * ratio + y0; }
  180. }
  181. else{
  182. point.x = MAX(minX, MIN(point.x, maxX));
  183. point.y = MAX(minY, MIN(point.y, maxY));
  184. }
  185. rct.size.width = point.x - rct.origin.x;
  186. rct.size.height = point.y - rct.origin.y;
  187. break;
  188. }
  189. default:
  190. break;
  191. }
  192. self.clippingRect = rct;
  193. }
  194. //移动裁剪view
  195. - (void)panGridView:(UIPanGestureRecognizer*)sender
  196. {
  197. static BOOL dragging = NO;
  198. static CGRect initialRect;
  199. if(sender.state==UIGestureRecognizerStateBegan){
  200. CGPoint point = [sender locationInView:self];
  201. dragging = CGRectContainsPoint(_clippingRect, point);
  202. initialRect = self.clippingRect;
  203. }
  204. else if(dragging){
  205. CGPoint point = [sender translationInView:self];
  206. CGFloat left = MIN(MAX(initialRect.origin.x + point.x, 0), self.frame.size.width-initialRect.size.width);
  207. CGFloat top = MIN(MAX(initialRect.origin.y + point.y, 0), self.frame.size.height-initialRect.size.height);
  208. CGRect rct = self.clippingRect;
  209. rct.origin.x = left;
  210. rct.origin.y = top;
  211. self.clippingRect = rct;
  212. }
  213. }
  214. @end