TabbarButton.m 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. //
  2. // TabbarButton.m
  3. // WFChat UIKit
  4. //
  5. // Created by WF Chat on 2017/9/12.
  6. // Copyright © 2017年 WildFireChat. All rights reserved.
  7. //
  8. #define kBtnWidth self.bounds.size.width
  9. #define kBtnHeight self.bounds.size.height
  10. #import "TabbarButton.h"
  11. #import "WFCUImage.h"
  12. NSString *const kTabBarClearBadgeNotification = @"kTabBarClearBadgeNotification";
  13. @interface TabbarButton()
  14. @end
  15. @implementation TabbarButton
  16. - (instancetype)initWithFrame:(CGRect)frame
  17. {
  18. if (self = [super initWithFrame:frame]) {
  19. [self setUp];
  20. }
  21. return self;
  22. }
  23. - (void)awakeFromNib
  24. {
  25. [super awakeFromNib];
  26. [self setUp];
  27. }
  28. //- (void)layoutSubviews
  29. //{
  30. // [self setUp];
  31. //}
  32. #pragma mark - 懒加载
  33. - (NSMutableArray *)images
  34. {
  35. if (_images == nil) {
  36. _images = [NSMutableArray array];
  37. for (int i = 1; i < 9; i++) {
  38. UIImage *image = [WFCUImage imageNamed:[NSString stringWithFormat:@"%d", i]];
  39. [_images addObject:image];
  40. }
  41. }
  42. return _images;
  43. }
  44. - (CAShapeLayer *)shapeLayer
  45. {
  46. if (!_shapeLayer) {
  47. _shapeLayer = [CAShapeLayer layer];
  48. _shapeLayer.fillColor = [self.backgroundColor CGColor];
  49. [self.superview.layer insertSublayer:_shapeLayer below:self.layer];
  50. }
  51. return _shapeLayer;
  52. }
  53. - (UIView *)samllCircleView
  54. {
  55. if (!_samllCircleView) {
  56. _samllCircleView = [[UIView alloc] init];
  57. _samllCircleView.backgroundColor = self.backgroundColor;
  58. [self.superview insertSubview:_samllCircleView belowSubview:self];
  59. }
  60. return _samllCircleView;
  61. }
  62. - (void)setUp
  63. {
  64. CGFloat cornerRadius = (kBtnHeight > kBtnWidth ? kBtnWidth / 2.0 : kBtnHeight / 2.0);
  65. self.backgroundColor = [UIColor redColor];
  66. [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  67. self.titleLabel.font = [UIFont systemFontOfSize:12.f];
  68. _maxDistance = cornerRadius * 5;
  69. self.layer.masksToBounds = YES;
  70. self.layer.cornerRadius = cornerRadius;
  71. CGRect samllCireleRect = CGRectMake(0, 0, cornerRadius * (2 - 0.5) , cornerRadius * (2 - 0.5));
  72. self.samllCircleView.bounds = samllCireleRect;
  73. _samllCircleView.center = self.center;
  74. _samllCircleView.layer.cornerRadius = _samllCircleView.bounds.size.width / 2;
  75. UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
  76. [self addGestureRecognizer:pan];
  77. // [self addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
  78. }
  79. #pragma mark - 手势
  80. - (void)pan:(UIPanGestureRecognizer *)pan
  81. {
  82. [self.layer removeAnimationForKey:@"shake"];
  83. CGPoint panPoint = [pan translationInView:self];
  84. CGPoint changeCenter = self.center;
  85. changeCenter.x += panPoint.x;
  86. changeCenter.y += panPoint.y;
  87. self.center = changeCenter;
  88. [pan setTranslation:CGPointZero inView:self];
  89. //俩个圆的中心点之间的距离
  90. CGFloat dist = [self pointToPoitnDistanceWithPoint:self.center potintB:self.samllCircleView.center];
  91. if (dist < _maxDistance) {
  92. CGFloat cornerRadius = (kBtnHeight > kBtnWidth ? kBtnWidth / 2 : kBtnHeight / 2);
  93. CGFloat samllCrecleRadius = cornerRadius - dist / 10;
  94. _samllCircleView.bounds = CGRectMake(0, 0, samllCrecleRadius * (2 - 0.5), samllCrecleRadius * (2 - 0.5));
  95. _samllCircleView.layer.cornerRadius = _samllCircleView.bounds.size.width / 2;
  96. if (_samllCircleView.hidden == NO && dist > 0) {
  97. //画不规则矩形
  98. self.shapeLayer.path = [self pathWithBigCirCleView:self smallCirCleView:_samllCircleView].CGPath;
  99. }
  100. } else {
  101. [self.shapeLayer removeFromSuperlayer];
  102. self.shapeLayer = nil;
  103. self.samllCircleView.hidden = YES;
  104. }
  105. if (pan.state == UIGestureRecognizerStateEnded) {
  106. if (dist > _maxDistance) {
  107. //播放销毁动画
  108. // [self startDestroyAnimations];
  109. //销毁全部控件
  110. [self killAll];
  111. } else {
  112. [self.shapeLayer removeFromSuperlayer];
  113. self.shapeLayer = nil;
  114. [UIView animateWithDuration:0.3 delay:0 usingSpringWithDamping:0.2 initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
  115. self.center = self.samllCircleView.center;
  116. } completion:^(BOOL finished) {
  117. self.samllCircleView.hidden = NO;
  118. }];
  119. }
  120. }
  121. }
  122. #pragma mark - 俩个圆心之间的距离
  123. - (CGFloat)pointToPoitnDistanceWithPoint:(CGPoint)pointA potintB:(CGPoint)pointB
  124. {
  125. CGFloat offestX = pointA.x - pointB.x;
  126. CGFloat offestY = pointA.y - pointB.y;
  127. CGFloat dist = sqrtf(offestX * offestX + offestY * offestY);
  128. return dist;
  129. }
  130. - (void)killAll
  131. {
  132. [self.samllCircleView removeFromSuperview];
  133. [self.shapeLayer removeFromSuperlayer];
  134. [self removeFromSuperview];
  135. [[NSNotificationCenter defaultCenter] postNotificationName:kTabBarClearBadgeNotification object:@(self.tag - 888)];
  136. }
  137. #pragma mark - 不规则路径
  138. - (UIBezierPath *)pathWithBigCirCleView:(UIView *)bigCirCleView smallCirCleView:(UIView *)smallCirCleView
  139. {
  140. CGPoint bigCenter = bigCirCleView.center;
  141. CGFloat x2 = bigCenter.x;
  142. CGFloat y2 = bigCenter.y;
  143. CGFloat r2 = bigCirCleView.bounds.size.height / 2;
  144. CGPoint smallCenter = smallCirCleView.center;
  145. CGFloat x1 = smallCenter.x;
  146. CGFloat y1 = smallCenter.y;
  147. CGFloat r1 = smallCirCleView.bounds.size.width / 2;
  148. // 获取圆心距离
  149. CGFloat d = [self pointToPoitnDistanceWithPoint:self.samllCircleView.center potintB:self.center];
  150. CGFloat sinθ = (x2 - x1) / d;
  151. CGFloat cosθ = (y2 - y1) / d;
  152. // 坐标系基于父控件
  153. CGPoint pointA = CGPointMake(x1 - r1 * cosθ , y1 + r1 * sinθ);
  154. CGPoint pointB = CGPointMake(x1 + r1 * cosθ , y1 - r1 * sinθ);
  155. CGPoint pointC = CGPointMake(x2 + r2 * cosθ , y2 - r2 * sinθ);
  156. CGPoint pointD = CGPointMake(x2 - r2 * cosθ , y2 + r2 * sinθ);
  157. CGPoint pointO = CGPointMake(pointA.x + d / 2 * sinθ , pointA.y + d / 2 * cosθ);
  158. CGPoint pointP = CGPointMake(pointB.x + d / 2 * sinθ , pointB.y + d / 2 * cosθ);
  159. UIBezierPath *path = [UIBezierPath bezierPath];
  160. // A
  161. [path moveToPoint:pointA];
  162. // AB
  163. [path addLineToPoint:pointB];
  164. // 绘制BC曲线
  165. [path addQuadCurveToPoint:pointC controlPoint:pointP];
  166. // CD
  167. [path addLineToPoint:pointD];
  168. // 绘制DA曲线
  169. [path addQuadCurveToPoint:pointA controlPoint:pointO];
  170. return path;
  171. }
  172. #pragma mark - button消失动画
  173. - (void)startDestroyAnimations
  174. {
  175. UIImageView *ainmImageView = [[UIImageView alloc] initWithFrame:self.frame];
  176. ainmImageView.animationImages = self.images;
  177. ainmImageView.animationRepeatCount = 1;
  178. ainmImageView.animationDuration = 0.5;
  179. [ainmImageView startAnimating];
  180. [self.superview addSubview:ainmImageView];
  181. }
  182. - (void)btnClick
  183. {
  184. }
  185. #pragma mark - 设置长按时候左右摇摆的动画
  186. - (void)setHighlighted:(BOOL)highlighted
  187. {
  188. [self.layer removeAnimationForKey:@"shake"];
  189. //长按左右晃动的幅度大小
  190. CGFloat shake = 3;
  191. CAKeyframeAnimation *keyAnim = [CAKeyframeAnimation animation];
  192. keyAnim.keyPath = @"transform.translation.x";
  193. keyAnim.values = @[@(-shake), @(shake), @(-shake)];
  194. keyAnim.removedOnCompletion = NO;
  195. keyAnim.repeatCount = 2;
  196. //左右晃动一次的时间
  197. keyAnim.duration = 0.3;
  198. if ( [self.layer animationForKey:@"shake"] == nil) {
  199. [self.layer addAnimation:keyAnim forKey:@"shake"];
  200. }
  201. }
  202. -(void)setUnreadCount:(NSString *)unreadCount
  203. {
  204. [self setTitle:unreadCount forState:UIControlStateNormal];
  205. }
  206. - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
  207. {
  208. CGRect bounds = self.bounds;
  209. //若原热区小于44x44,则放大热区,否则保持原大小不变
  210. // CGFloat widthDelta = MAX(44.0 - bounds.size.width, 0);
  211. // CGFloat heightDelta = MAX(44.0 - bounds.size.height, 0);
  212. bounds = CGRectInset(bounds, 3, 3);
  213. //Todo: check is the message table
  214. return CGRectContainsPoint(bounds, point);
  215. }
  216. -(void)dealloc {
  217. [[NSNotificationCenter defaultCenter] removeObserver:self];
  218. }
  219. @end