HWPanModalPresentable.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. //
  2. // HWPanModalPresentable.h
  3. // Pods
  4. //
  5. // Created by heath wang on 2019/4/26.
  6. //
  7. #import <Foundation/Foundation.h>
  8. #import <UIKit/UIKit.h>
  9. #import "HWPanModalHeight.h"
  10. #import "HWPresentingVCAnimatedTransitioning.h"
  11. #import "HWPanModalIndicatorProtocol.h"
  12. NS_ASSUME_NONNULL_BEGIN
  13. typedef NS_ENUM(NSInteger, PresentationState) {
  14. PresentationStateShort NS_SWIFT_NAME(short),
  15. PresentationStateLong NS_SWIFT_NAME(long),
  16. };
  17. typedef void(^AnimationBlockType)(void);
  18. typedef void(^AnimationCompletionType)(BOOL completion);
  19. /**
  20. * HWPanModalPresentable为present配置协议
  21. * 默认情况下无需实现,只需Controller conforms 该协议
  22. * 通过category来默认实现以下所有方法。这样就不用通过继承来实现protocol
  23. */
  24. @protocol HWPanModalPresentable <NSObject>
  25. #pragma mark - ScrollView Config
  26. /**
  27. * 支持同步拖拽的scrollView
  28. * 如果ViewController中包含scrollView并且你想scrollView滑动和拖拽手势同事存在,请返回此scrollView
  29. */
  30. - (nullable UIScrollView *)panScrollable;
  31. /**
  32. * determine ScrollView scrollEnabled
  33. * 默认为YES
  34. */
  35. - (BOOL)isPanScrollEnabled;
  36. /**
  37. * scrollView指示器insets
  38. * Use `panModalSetNeedsLayoutUpdate()` when updating insets.
  39. */
  40. - (UIEdgeInsets)scrollIndicatorInsets;
  41. /**
  42. * 是否允许拖动额外拖动,如果panScrollable存在,且scrollView contentSize > (size + bottomLayoutOffset),返回YES
  43. * 其余情况返回NO
  44. */
  45. - (BOOL)allowsExtendedPanScrolling;
  46. #pragma mark - Offset/position
  47. /**
  48. * offset:屏幕顶部距离
  49. * 默认为topLayoutGuide.length + 21.0.
  50. */
  51. - (CGFloat)topOffset;
  52. /**
  53. * 当pan状态为short时候的高度
  54. * 默认状态下,shortFormHeight = longFormHeight
  55. */
  56. - (PanModalHeight)shortFormHeight;
  57. /**
  58. * 当pan状态为long的高度
  59. */
  60. - (PanModalHeight)longFormHeight;
  61. #pragma mark - Animation config
  62. /**
  63. * spring弹性动画数值,默认未0.9
  64. */
  65. - (CGFloat)springDamping;
  66. /**
  67. * 转场动画时间,默认为0.5s
  68. */
  69. - (NSTimeInterval)transitionDuration;
  70. /**
  71. * 转场动画options
  72. * 默认为 UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState
  73. */
  74. - (UIViewAnimationOptions)transitionAnimationOptions;
  75. #pragma mark - Background config
  76. /**
  77. * 背景透明度,默认为0.7
  78. */
  79. - (CGFloat)backgroundAlpha;
  80. /**
  81. * Blur background
  82. * This function can NOT coexist with backgroundAlpha
  83. * Default use backgroundAlpha, Once you set backgroundBlurRadius > 0, blur will work.
  84. * I recommend set the value 10 ~ 20.
  85. * @return blur radius
  86. */
  87. - (CGFloat)backgroundBlurRadius;
  88. /**
  89. * blur background color
  90. * @return color, default is White Color.
  91. */
  92. - (nonnull UIColor *)backgroundBlurColor;
  93. #pragma mark - User operation
  94. /**
  95. * 该bool值控制当pan View状态为long的情况下,是否可以继续拖拽到PanModalHeight = MAX的情况
  96. * 默认为YES,即当已经拖拽到long的情况下不能再继续拖动
  97. */
  98. - (BOOL)anchorModalToLongForm;
  99. /**
  100. * 是否允许点击背景处dismiss presented Controller
  101. * 默认为YES
  102. */
  103. - (BOOL)allowsTapBackgroundToDismiss;
  104. /**
  105. * 是否允许drag操作dismiss presented Controller
  106. * 默认为YES
  107. */
  108. - (BOOL)allowsDragToDismiss;
  109. /**
  110. * 是否允许用户操作
  111. * 默认为YES
  112. */
  113. - (BOOL)isUserInteractionEnabled;
  114. /**
  115. * 是否允许屏幕边缘侧滑手势
  116. * 默认为NO,不允许
  117. */
  118. - (BOOL)allowScreenEdgeInteractive;
  119. /**
  120. * 是否允许触觉反馈
  121. * 默认为YES
  122. */
  123. - (BOOL)isHapticFeedbackEnabled;
  124. #pragma mark - Custom presentingViewController animation
  125. /**
  126. * 是否对presentingViewController做动画效果,默认该效果类似淘宝/京东购物车凹陷效果
  127. * 默认为NO
  128. */
  129. - (BOOL)shouldAnimatePresentingVC;
  130. /**
  131. * 自定义presenting ViewController转场动画
  132. * 注意要使自定义效果生效,shouldAnimatePresentingVC 必须返回YES
  133. * 默认转场效果为凹陷动画效果,如果该方法返回不为空,则使用自定义动画效果
  134. * 默认为nil
  135. */
  136. - (nullable id<HWPresentingViewControllerAnimatedTransitioning>)customPresentingVCAnimation;
  137. #pragma mark - Content UI config
  138. /**
  139. * 是否顶部圆角
  140. * 默认为YES
  141. */
  142. - (BOOL)shouldRoundTopCorners;
  143. /**
  144. * 顶部圆角数值
  145. * 默认为8.0
  146. */
  147. - (CGFloat)cornerRadius;
  148. #pragma mark - Indicator config
  149. /**
  150. * 是否显示drag指示view
  151. * 默认为YES,该属性默认取‘- (BOOL)shouldRoundTopCorners’
  152. */
  153. - (BOOL)showDragIndicator;
  154. /**
  155. * You can make the indicator customized. Just adopt `HWPanModalIndicatorProtocol`
  156. * Default this method return nil, Then the default indicator will be used.
  157. */
  158. - (__kindof UIView<HWPanModalIndicatorProtocol> * _Nullable)customIndicatorView;
  159. #pragma mark - Keyboard handle
  160. /**
  161. * When there is text input view exists and becomeFirstResponder, will auto handle keyboard height.
  162. * Default is YES. You can disable it, handle it by yourself.
  163. */
  164. - (BOOL)isAutoHandleKeyboardEnabled;
  165. /**
  166. The offset that keyboard show from input view's bottom. It works when
  167. `isAutoHandleKeyboardEnabled` return YES.
  168. @return offset, default is 5.
  169. */
  170. - (CGFloat)keyboardOffsetFromInputView;
  171. #pragma mark - Delegate
  172. #pragma mark - Pan Gesture delegate
  173. /**
  174. * 询问delegate是否需要使拖拽手势生效
  175. * 若返回NO,则禁用拖拽手势操作
  176. * 默认为YES
  177. */
  178. - (BOOL)shouldRespondToPanModalGestureRecognizer:(nonnull UIPanGestureRecognizer *)panGestureRecognizer;
  179. /**
  180. * 当pan recognizer状态为begin/changed时,通知delegate回调。
  181. * 当拖动presented View时,该方法会持续的回调
  182. * 默认实现为空
  183. */
  184. - (void)willRespondToPanModalGestureRecognizer:(nonnull UIPanGestureRecognizer *)panGestureRecognizer;
  185. /**
  186. * 是否优先执行dismiss拖拽手势,当存在panScrollable的情况下,如果此方法返回YES,则
  187. * dismiss手势生效,scrollView本身的滑动则不再生效。也就是说可以拖动Controller view,而scrollView没法拖动了。
  188. *
  189. * 例子:controller view上添加一个TableView,并铺满全屏,然后在controller view 顶部添加一个一定大小的viewA,
  190. * 这个时候会发现viewA有时候无法拖动,可以实现此delegate方法来解决
  191. ```
  192. - (BOOL)shouldPrioritizePanModalGestureRecognizer:(UIPanGestureRecognizer *)panGestureRecognizer {
  193. CGPoint loc = [panGestureRecognizer locationInView:self.view];
  194. // check whether user pan action in viewA
  195. if (CGRectContainsPoint(self.viewA.frame, loc)) {
  196. return YES;
  197. }
  198. return NO;
  199. }
  200. ```
  201. * 默认为NO
  202. *
  203. * This delegate is useful when you want panGestureRecognizer has a high prioritize and
  204. * make scrollable does NOT scroll.
  205. * Example: You controller add a full size tableView, then add viewA on top of your controller view.
  206. * Now you find you can not drag the viewA, use this delegate to resolve problem.
  207. * Please refer to code above this comment.
  208. *
  209. * Default is NO
  210. */
  211. - (BOOL)shouldPrioritizePanModalGestureRecognizer:(nonnull UIPanGestureRecognizer *)panGestureRecognizer;
  212. /**
  213. * When you pan present controller to dismiss, and the view's y <= shortFormYPos,
  214. * this delegate method will be called.
  215. * @param percent 0 ~ 1, 1 means has dismissed
  216. */
  217. - (void)panModalGestureRecognizer:(nonnull UIPanGestureRecognizer *)panGestureRecognizer dismissPercent:(CGFloat)percent;
  218. #pragma mark - PresentationState change delegate
  219. /**
  220. * 是否应该变更panModal状态
  221. */
  222. - (BOOL)shouldTransitionToState:(PresentationState)state;
  223. /**
  224. * 通知回调即将变更状态
  225. */
  226. - (void)willTransitionToState:(PresentationState)state;
  227. #pragma mark - Dismiss delegate
  228. /**
  229. * will dismiss
  230. */
  231. - (void)panModalWillDismiss;
  232. /**
  233. * Did finish dismissing
  234. */
  235. - (void)panModalDidDismissed;
  236. @end
  237. NS_ASSUME_NONNULL_END