XYFloatingDragView.m 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. //
  2. // XYFloatingDragView.m
  3. // Starbuds
  4. //
  5. // Created by 翟玉磊 on 2020/6/29.
  6. // Copyright © 2020 翟玉磊. All rights reserved.
  7. //
  8. #import "XYFloatingDragView.h"
  9. @interface XYFloatingDragView ()
  10. /// 悬浮按钮的拖拽范围 不设置则默认父view的bounds
  11. @property (nonatomic, assign) CGRect cagingArea;
  12. /// 停留样式 默认 无吸附边界
  13. @property (nonatomic, assign) XYFloatingDragAutomaticStyle remainStyle;
  14. /// 内容类型 默认语音
  15. @property (nonatomic, assign) XYFloatingDragType floatingDataType;
  16. @end
  17. @implementation XYFloatingDragView
  18. #pragma mark - Public
  19. // 根据类型创建悬浮窗 会默认好初始值
  20. + (instancetype)floatingDragViewWithFloatingDragType:(XYFloatingDragType)type {
  21. XYFloatingDragView *floatingDragView = nil;
  22. switch (type) {
  23. case XYFloatingDragTypeVoiceChatRoom:
  24. {
  25. CGRect cagingArea = CGRectMake(0, NAVGATION_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - NAVGATION_HEIGHT - TABBAR_HEIGHT);
  26. floatingDragView = [[XYFloatingDragView alloc] initWithFrame:CGRectMake(SCREEN_WIDTH - 162.0f, cagingArea.size.height - 48.0f, 162.0f, 48.0f)];
  27. floatingDragView.floatingDataType = type;
  28. floatingDragView.cagingArea = cagingArea;
  29. floatingDragView.remainStyle = XYFloatingDragAutomaticStyleMargin;
  30. // 语音view
  31. XYFloatingDragVoiceView *voiceView = [[XYFloatingDragVoiceView alloc] initWithFrame:floatingDragView.bounds];
  32. [floatingDragView addSubview:voiceView];
  33. floatingDragView.voiceView = voiceView;
  34. [voiceView setCloseFloatingDragBlock:^{
  35. if (floatingDragView.delegate && [floatingDragView.delegate respondsToSelector:@selector(closeFloatingDragWindow)]) {
  36. [floatingDragView.delegate closeFloatingDragWindow];
  37. }
  38. [floatingDragView dismissAnimation:YES];
  39. }];
  40. }
  41. break;
  42. default:
  43. break;
  44. }
  45. return floatingDragView;
  46. }
  47. /// 显示view
  48. - (void)showAnimation:(BOOL)animation {
  49. if (!self.superview) {
  50. // 没有父view则进行添加
  51. [ApplicationDelegate.tabbarVC.view addSubview:self];
  52. }
  53. // 把悬浮窗移到最上层
  54. [ApplicationDelegate.tabbarVC.view bringSubviewToFront:self];
  55. if (animation) {
  56. [UIView animateWithDuration:.3 animations:^{
  57. self.alpha = 1;
  58. } completion:^(BOOL finished) {
  59. }];
  60. }
  61. }
  62. /// 隐藏view且销毁view
  63. - (void)dismissAnimation:(BOOL)animation {
  64. if (animation) {
  65. [UIView animateWithDuration:.3 animations:^{
  66. self.alpha = 0;
  67. } completion:^(BOOL finished) {
  68. [self clear];
  69. }];
  70. }else {
  71. [self clear];
  72. }
  73. }
  74. /// 设置view信息
  75. - (void)setupViewDataWithModel:(id)model {
  76. switch (self.floatingDataType) {
  77. case XYFloatingDragTypeVoiceChatRoom:
  78. if (self.voiceView) {
  79. [self.voiceView setupViewDataWithModel:model];
  80. }
  81. break;
  82. default:
  83. break;
  84. }
  85. }
  86. /// 销毁view
  87. - (void)clear {
  88. switch (self.floatingDataType) {
  89. case XYFloatingDragTypeVoiceChatRoom:
  90. if (self.voiceView) {
  91. [self.voiceView clear];
  92. [self.voiceView removeFromSuperview];
  93. }
  94. break;
  95. default:
  96. break;
  97. }
  98. }
  99. #pragma mark - Action
  100. // 拖动手势处理
  101. - (void)handlePan:(UIPanGestureRecognizer *)sender {
  102. if(sender.state == UIGestureRecognizerStateChanged){
  103. {
  104. CGPoint translation = [sender translationInView:[self superview]];
  105. CGFloat newXOrigin = CGRectGetMinX(self.frame) + translation.x;
  106. CGFloat newYOrigin = CGRectGetMinY(self.frame) + translation.y;
  107. CGRect cagingArea = self.cagingArea;
  108. CGFloat cagingAreaOriginX = CGRectGetMinX(cagingArea);
  109. CGFloat cagingAreaOriginY = CGRectGetMinY(cagingArea);
  110. CGFloat cagingAreaRightSide = cagingAreaOriginX + CGRectGetWidth(cagingArea);
  111. CGFloat cagingAreaBottomSide = cagingAreaOriginY + CGRectGetHeight(cagingArea);
  112. if (!CGRectEqualToRect(cagingArea, CGRectZero)) {
  113. if (newXOrigin <= cagingAreaOriginX ||
  114. newXOrigin + CGRectGetWidth(self.frame) >= cagingAreaRightSide) {
  115. newXOrigin = CGRectGetMinX(self.frame);
  116. }
  117. if(newYOrigin <= cagingAreaOriginY ||
  118. newYOrigin + CGRectGetHeight(self.frame) >= cagingAreaBottomSide) {
  119. newYOrigin = CGRectGetMinY(self.frame);
  120. }
  121. }
  122. self.frame = CGRectMake(newXOrigin,
  123. newYOrigin,
  124. CGRectGetWidth(self.frame),
  125. CGRectGetHeight(self.frame));
  126. [sender setTranslation:(CGPoint){0, 0} inView:[self superview]];
  127. }
  128. }else if (sender.state == UIGestureRecognizerStateEnded){
  129. CGSize dragBtnSize = self.frame.size;
  130. CGFloat dragBtn_Y = CGRectGetMinY(self.frame);
  131. CGFloat dragBtn_X = 0;
  132. CGFloat duration = 0.7;//默认时间
  133. //计算出按钮距离边界的差 用作动画时间的计算
  134. CGFloat difference = 1.0;
  135. switch (_remainStyle) {
  136. case XYFloatingDragAutomaticStyleNone:
  137. return;
  138. case XYFloatingDragAutomaticStyleMargin:
  139. {
  140. if (self.center.x >= self.cagingArea.size.width / 2.0) {
  141. //右
  142. dragBtn_X = self.cagingArea.size.width - dragBtnSize.width;
  143. difference = (self.cagingArea.size.width - CGRectGetMaxX(self.frame)) / self.cagingArea.size.width;
  144. }else{
  145. //左
  146. dragBtn_X = 0;
  147. difference = CGRectGetMidX(self.frame) / self.cagingArea.size.width;
  148. }
  149. }
  150. break;
  151. case XYFloatingDragAutomaticStyleMarginLeft:
  152. dragBtn_X = 0;
  153. difference = CGRectGetMidX(self.frame) / self.cagingArea.size.width;
  154. break;
  155. case XYFloatingDragAutomaticStyleMarginRight:
  156. dragBtn_X = self.cagingArea.size.width - dragBtnSize.width;
  157. difference = (self.cagingArea.size.width - CGRectGetMaxX(self.frame)) / self.cagingArea.size.width;
  158. break;
  159. default:
  160. break;
  161. }
  162. //距离越近。动画时间就越短
  163. duration = duration * difference;
  164. [UIView animateWithDuration:duration animations:^{
  165. self.frame = CGRectMake(dragBtn_X, dragBtn_Y, dragBtnSize.width, dragBtnSize.height);
  166. }];
  167. }
  168. }
  169. // 处理 点击事件
  170. - (void)handleTap:(UITapGestureRecognizer *)sender {
  171. if (self.delegate && [self.delegate respondsToSelector:@selector(openFloatingDragWindow)]) {
  172. [self.delegate openFloatingDragWindow];
  173. }
  174. }
  175. #pragma mark - 初始化
  176. - (instancetype)initWithFrame:(CGRect)frame {
  177. if (self = [super initWithFrame:frame]) {
  178. [self _setup];
  179. [self _setupSubViews];
  180. [self _makeSubViewsConstraint];
  181. }
  182. return self;
  183. }
  184. #pragma mark - 配置属性
  185. - (void)_setup {
  186. // 添加手势
  187. UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
  188. [self addGestureRecognizer:pan];
  189. UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
  190. [self addGestureRecognizer:tap];
  191. }
  192. #pragma mark - 设置子控件
  193. - (void)_setupSubViews {
  194. }
  195. #pragma mark - 布局子控件
  196. - (void)_makeSubViewsConstraint {
  197. // 设置边框和阴影
  198. [self addViewShadowWithShadowColor:ColorFromHexStringWithAlpha(@"#FF4D79", 0.5f) shadowOffset:CGSizeMake(0, 4) shadowOpacity:1 shadowRadius:10.0f cornerRadius:self.f_heigh/2];
  199. }
  200. #pragma mark - Getter/Setter
  201. - (CGRect)cagingArea {
  202. if (_cagingArea.size.width == 0 || _cagingArea.size.height == 0) {
  203. // 可拖动范围如果宽高有一项为空则默认父控制器的bounds
  204. if (self.superview) {
  205. _cagingArea = self.superview.bounds;
  206. }
  207. }
  208. return _cagingArea;
  209. }
  210. @end