SwipeView.m 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. //
  2. // SwipeView.m
  3. // SwipeTableView
  4. //
  5. // Created by zhao on 16/8/29.
  6. // Copyright © 2016年 zhaoName. All rights reserved.
  7. //
  8. #import "SwipeView.h"
  9. #import "SwipeButton.h"
  10. #import "SwipeTableCell.h"
  11. static inline CGFloat mgEaseLinear(CGFloat t, CGFloat b, CGFloat c) {
  12. return c*t + b;
  13. }
  14. static inline CGFloat mgEaseInQuad(CGFloat t, CGFloat b, CGFloat c) {
  15. return c*t*t + b;
  16. }
  17. static inline CGFloat mgEaseOutQuad(CGFloat t, CGFloat b, CGFloat c) {
  18. return -c*t*(t-2) + b;
  19. }
  20. static inline CGFloat mgEaseInOutQuad(CGFloat t, CGFloat b, CGFloat c) {
  21. if ((t*=2) < 1) return c/2*t*t + b;
  22. --t;
  23. return -c/2 * (t*(t-2) - 1) + b;
  24. }
  25. static inline CGFloat mgEaseInCubic(CGFloat t, CGFloat b, CGFloat c) {
  26. return c*t*t*t + b;
  27. }
  28. static inline CGFloat mgEaseOutCubic(CGFloat t, CGFloat b, CGFloat c) {
  29. --t;
  30. return c*(t*t*t + 1) + b;
  31. }
  32. static inline CGFloat mgEaseInOutCubic(CGFloat t, CGFloat b, CGFloat c) {
  33. if ((t*=2) < 1) return c/2*t*t*t + b;
  34. t-=2;
  35. return c/2*(t*t*t + 2) + b;
  36. }
  37. static inline CGFloat mgEaseOutBounce(CGFloat t, CGFloat b, CGFloat c) {
  38. if (t < (1/2.75)) {
  39. return c*(7.5625*t*t) + b;
  40. } else if (t < (2/2.75)) {
  41. t-=(1.5/2.75);
  42. return c*(7.5625*t*t + .75) + b;
  43. } else if (t < (2.5/2.75)) {
  44. t-=(2.25/2.75);
  45. return c*(7.5625*t*t + .9375) + b;
  46. } else {
  47. t-=(2.625/2.75);
  48. return c*(7.5625*t*t + .984375) + b;
  49. }
  50. };
  51. static inline CGFloat mgEaseInBounce(CGFloat t, CGFloat b, CGFloat c) {
  52. return c - mgEaseOutBounce (1.0 -t, 0, c) + b;
  53. };
  54. static inline CGFloat mgEaseInOutBounce(CGFloat t, CGFloat b, CGFloat c) {
  55. if (t < 0.5) return mgEaseInBounce (t*2, 0, c) * .5 + b;
  56. return mgEaseOutBounce (1.0 - t*2, 0, c) * .5 + c*.5 + b;
  57. };
  58. @interface SwipeView ()
  59. @property (nonatomic, strong) UIView *containView; /**< 装swipeButton的容器*/
  60. @property (nonatomic, strong) NSArray *buttonArray; /**< 重新排序后的buttons*/
  61. @property (nonatomic, assign) UIEdgeInsets btnEdge; /**< swipeBtn间距*/
  62. @end
  63. @implementation SwipeView
  64. - (instancetype)initWithButtons:(NSArray *)buttos fromRight:(BOOL)fromRight cellHeght:(CGFloat)cellHeight edge:(UIEdgeInsets)edge
  65. {
  66. CGFloat containerWidth = 0;
  67. CGFloat horizontalSpace = ABS(edge.left) + ABS(edge.right);
  68. CGFloat verticalSpace = ABS(edge.top) + ABS(edge.bottom);
  69. // 计算buttons的总宽度
  70. for(SwipeButton *button in buttos){
  71. containerWidth += MAX(button.frame.size.width, cellHeight - verticalSpace);
  72. }
  73. // 加上左右间距
  74. containerWidth += horizontalSpace;
  75. if([super initWithFrame:CGRectMake(0, 0, containerWidth, cellHeight - verticalSpace)])
  76. {
  77. self.btnEdge = edge;
  78. self.duration = 0.3;
  79. self.easingFunction = MGSwipeEasingFunctionCubicOut;
  80. self.containView.frame = CGRectMake(0, ABS(edge.top), containerWidth, cellHeight - verticalSpace);
  81. // 若是右滑 则倒序。即将数组的最后一个元素放在swipeView的最后
  82. self.buttonArray = fromRight ? [[buttos reverseObjectEnumerator] allObjects] : buttos;
  83. [self addSubview:self.containView];
  84. CGFloat offset = ABS(edge.left);
  85. for(SwipeButton *button in self.buttonArray)
  86. {
  87. button.frame = CGRectMake(offset, 0, MAX(button.frame.size.width, cellHeight - verticalSpace), cellHeight - verticalSpace);
  88. offset += button.frame.size.width;
  89. // 防止重用问题,移除点击事件
  90. [button removeTarget:self action:@selector(touchSwipeButton:) forControlEvents:UIControlEventTouchUpInside];
  91. [button addTarget:self action:@selector(touchSwipeButton:) forControlEvents:UIControlEventTouchUpInside];
  92. // 直接用addSubview会覆盖左滑的动画效果
  93. [self.containView insertSubview:button atIndex:fromRight ? self.containView.subviews.count : 0];
  94. }
  95. }
  96. return self;
  97. }
  98. /**
  99. * 点击滑动按钮的响应事件
  100. */
  101. - (void)touchSwipeButton:(SwipeButton *)btn
  102. {
  103. // 点击按钮隐藏滑动按钮,即将cell恢复原状
  104. [self hideSwipeView];
  105. // 点击按钮的回调事件
  106. btn.touchBlock();
  107. }
  108. /**
  109. * 点击SwipeButton隐藏SwipeView,即将cell恢复原状
  110. */
  111. - (void)hideSwipeView
  112. {
  113. SwipeTableCell *cell = nil;
  114. UIView *view = self.superview;
  115. while (view != nil)
  116. {
  117. if([view isKindOfClass:[SwipeTableCell class]])
  118. {
  119. cell = (SwipeTableCell *)view;
  120. break;
  121. }
  122. view = view.superview;
  123. }
  124. if(cell.swipeDelegate && [cell.swipeDelegate respondsToSelector:@selector(hideSwipeViewWhenClickSwipeButtonAtCell:)])
  125. {
  126. cell.hideSwipeViewWhenClickSwipeButton = [cell.swipeDelegate hideSwipeViewWhenClickSwipeButtonAtCell:cell];
  127. }
  128. [cell hiddenSwipeAnimationAtCell:cell.hideSwipeViewWhenClickSwipeButton];
  129. }
  130. #pragma mark -- 动画效果
  131. // 手势动画效果
  132. -(CGFloat)value:(CGFloat)elapsed duration:(CGFloat)duration from:(CGFloat)from to:(CGFloat)to
  133. {
  134. CGFloat t = MIN(elapsed/duration, 1.0f);
  135. if (t == 1.0) {
  136. return to;
  137. }
  138. CGFloat (*easingFunction)(CGFloat t, CGFloat b, CGFloat c) = 0;
  139. switch (_easingFunction) {
  140. case MGSwipeEasingFunctionLinear: easingFunction = mgEaseLinear; break;
  141. case MGSwipeEasingFunctionQuadIn: easingFunction = mgEaseInQuad; break;
  142. case MGSwipeEasingFunctionQuadOut: easingFunction = mgEaseOutQuad; break;
  143. case MGSwipeEasingFunctionQuadInOut: easingFunction = mgEaseInOutQuad; break;
  144. case MGSwipeEasingFunctionCubicIn: easingFunction = mgEaseInCubic; break;
  145. default:
  146. case MGSwipeEasingFunctionCubicOut: easingFunction = mgEaseOutCubic;break;
  147. case MGSwipeEasingFunctionCubicInOut: easingFunction = mgEaseInOutCubic;break;
  148. case MGSwipeEasingFunctionBounceIn: easingFunction = mgEaseInBounce;break;
  149. case MGSwipeEasingFunctionBounceOut: easingFunction = mgEaseOutBounce;break;
  150. case MGSwipeEasingFunctionBounceInOut: easingFunction = mgEaseInOutBounce;break;
  151. }
  152. return (*easingFunction)(t, from, to - from);
  153. }
  154. // swipeView的弹出动画效果
  155. - (void)swipeViewAnimationFromRight:(BOOL)fromRight effect:(CGFloat)t cellHeight:(CGFloat)cellHeight
  156. {
  157. CGFloat verticalSpace = self.btnEdge.top + self.btnEdge.bottom;
  158. switch (self.mode)
  159. {
  160. case SwipeViewTransfromModeDefault:break; // 默认的效果
  161. case SwipeViewTransfromModeStatic:
  162. {
  163. const CGFloat dx = self.bounds.size.width * (1.0 - t);
  164. CGFloat offsetX = ABS(self.btnEdge.left);
  165. for (UIView *button in self.buttonArray) {
  166. CGRect frame = button.frame;
  167. frame.origin.x = offsetX + (fromRight ? -dx : dx);
  168. button.frame = frame;
  169. offsetX += frame.size.width;
  170. }
  171. }
  172. break;
  173. case SwipeViewTransfromModeBorder: // 渐出
  174. {
  175. CGFloat selfWidth = self.bounds.size.width;
  176. CGFloat offsetX = ABS(self.btnEdge.left);
  177. for (SwipeButton *button in self.buttonArray)
  178. {
  179. CGRect frame = button.frame;
  180. CGFloat x = fromRight ? offsetX * t : (selfWidth - MAX(frame.size.width, cellHeight - verticalSpace) - offsetX) * (1.0 - t) + offsetX;
  181. button.frame = CGRectMake(x, 0, MAX(frame.size.width, cellHeight - verticalSpace), cellHeight - verticalSpace);
  182. offsetX += MAX(frame.size.width, cellHeight - verticalSpace);
  183. }
  184. }
  185. break;
  186. case SwipeViewTransfromMode3D: // 3D
  187. {
  188. const CGFloat invert = fromRight ? -1.0 : 1.0;
  189. const CGFloat angle = M_PI_2 * (1.0 - t) * invert;
  190. CATransform3D transform = CATransform3DIdentity;
  191. transform.m34 = -1.0/400.0f;
  192. const CGFloat dx = -_containView.frame.size.width * 0.5 * invert;
  193. const CGFloat offset = dx * 2 * (1.0-t);
  194. transform = CATransform3DTranslate(transform, dx - offset, 0, 0);
  195. transform = CATransform3DRotate(transform, angle, 0.0, 1.0, 0.0);
  196. transform = CATransform3DTranslate(transform, -dx, 0, 0);
  197. self.containView.layer.transform = transform;
  198. }
  199. break;
  200. }
  201. }
  202. - (void)removeAllSubViewsAtView:(UIView *)view
  203. {
  204. while (view.subviews.count) {
  205. [[view.subviews lastObject] removeFromSuperview];
  206. }
  207. }
  208. #pragma mark -- 懒加载
  209. - (UIView *)containView
  210. {
  211. if(!_containView)
  212. {
  213. _containView = [[UIView alloc] initWithFrame:self.bounds];
  214. _containView.backgroundColor = [UIColor clearColor];
  215. _containView.clipsToBounds = YES;
  216. }
  217. return _containView;
  218. }
  219. - (NSArray *)buttonArray
  220. {
  221. if(!_buttonArray)
  222. {
  223. _buttonArray = [NSArray array];
  224. }
  225. return _buttonArray;
  226. }
  227. @end