TabbarButton.m 8.2 KB

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