HWPanModalPresentable.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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 <HWPanModal/HWPanModalHeight.h>
  10. #import <HWPanModal/HWPresentingVCAnimatedTransitioning.h>
  11. #import <HWPanModal/HWPanModalIndicatorProtocol.h>
  12. #import <HWPanModal/HWBackgroundConfig.h>
  13. #import <HWPanModal/HWPanModalShadow.h>
  14. NS_ASSUME_NONNULL_BEGIN
  15. typedef NS_ENUM(NSInteger, PresentationState) {
  16. PresentationStateShort NS_SWIFT_NAME(short),
  17. PresentationStateMedium NS_SWIFT_NAME(medium),
  18. PresentationStateLong NS_SWIFT_NAME(long),
  19. };
  20. typedef NS_ENUM(NSInteger, PresentingViewControllerAnimationStyle) {
  21. // no animation for presentingVC
  22. PresentingViewControllerAnimationStyleNone NS_SWIFT_NAME(none),
  23. // page sheet animation, like iOS13 default modalPresentation style
  24. PresentingViewControllerAnimationStylePageSheet NS_SWIFT_NAME(pageSheet),
  25. // shopping cart animation, like jd/taobao shopping cart animation
  26. PresentingViewControllerAnimationStyleShoppingCart NS_SWIFT_NAME(shoppingCart),
  27. // make your own custom animation
  28. PresentingViewControllerAnimationStyleCustom NS_SWIFT_NAME(custom),
  29. };
  30. /**
  31. * HWPanModalPresentable为present配置协议
  32. * 默认情况下无需实现,只需Controller/View适配该协议
  33. * 通过category来默认实现以下所有方法,避免继承类
  34. *
  35. * This Protocol is the core of HWPanModal, we use it to config presentation.
  36. * Default, you don't need to conform all of these methods, just implement what you want to customize.
  37. * All the config has default value, we use a `UIViewController` category to conform `HWPanModalPresentable` protocol.
  38. */
  39. @protocol HWPanModalPresentable <NSObject>
  40. #pragma mark - ScrollView Config
  41. /**
  42. * 支持同步拖拽的scrollView
  43. * 如果ViewController中包含scrollView并且你想scrollView滑动和拖拽手势同时存在,请返回此scrollView
  44. *
  45. * If your ViewController has a scrollable view(UIScrollView and subclass), and you want pan gesture and scrollable both work, return it.
  46. */
  47. - (nullable UIScrollView *)panScrollable;
  48. /**
  49. * determine ScrollView scrollEnabled
  50. * default is YES
  51. */
  52. - (BOOL)isPanScrollEnabled;
  53. /**
  54. * scrollView指示器insets
  55. * Use `panModalSetNeedsLayoutUpdate()` when updating insets.
  56. */
  57. - (UIEdgeInsets)scrollIndicatorInsets;
  58. /**
  59. * A Boolean value that controls whether the scrollable vertical scroll indicator is visible.
  60. * default is YES.
  61. */
  62. - (BOOL)showsScrollableVerticalScrollIndicator;
  63. /**
  64. * default is YES.
  65. */
  66. - (BOOL)shouldAutoSetPanScrollContentInset;
  67. /**
  68. * 是否允许拖动额外拖动,如果panScrollable存在,且scrollView contentSize > (size + bottomLayoutOffset),返回YES
  69. * 其余情况返回NO
  70. *
  71. * If panScrollable exists, and scrollView contentSize > (size + bottomLayoutOffset), auto return YES, otherwise return NO.
  72. * You can make your own logic if you want, and you know what you are doing.
  73. */
  74. - (BOOL)allowsExtendedPanScrolling;
  75. #pragma mark - Offset/position
  76. /**
  77. * Screen top offset from presented viewController
  78. * Default is topLayoutGuide.length + 21.0.
  79. */
  80. - (CGFloat)topOffset;
  81. /**
  82. * 当pan状态为short时候的高度
  83. * default: shortFormHeight = longFormHeight
  84. */
  85. - (PanModalHeight)shortFormHeight;
  86. /**
  87. * default: mediumFormHeight = longFormHeight
  88. */
  89. - (PanModalHeight)mediumFormHeight;
  90. /**
  91. * 当pan状态为long的高度
  92. */
  93. - (PanModalHeight)longFormHeight;
  94. /**
  95. * 初始弹出高度状态,默认为`shortFormHeight`
  96. *
  97. * Origin presentation height state, if you have special requirement, change it.
  98. * Default is `shortFormHeight`
  99. */
  100. - (PresentationState)originPresentationState;
  101. #pragma mark - Animation config
  102. /**
  103. * spring弹性动画数值
  104. * Default is 0.9
  105. */
  106. - (CGFloat)springDamping;
  107. /**
  108. * 转场动画时间
  109. * Default is 0.5 second
  110. */
  111. - (NSTimeInterval)transitionDuration;
  112. /**
  113. * starting from version 0.6.5, Only works when dismiss
  114. * Default is same as `- (NSTimeInterval)transitionDuration;`
  115. */
  116. - (NSTimeInterval)dismissalDuration;
  117. /**
  118. * 转场动画options
  119. * Default is UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState
  120. */
  121. - (UIViewAnimationOptions)transitionAnimationOptions;
  122. #pragma mark - AppearanceTransition
  123. /**
  124. * If enabled, the presenting VC will invoke viewWillAppear:, viewWillDisappear:
  125. * Default is YES
  126. */
  127. - (BOOL)shouldEnableAppearanceTransition;
  128. #pragma mark - Background config
  129. /**
  130. * use this object to config background alpha or blur effect
  131. * @return background config object
  132. */
  133. - (HWBackgroundConfig *)backgroundConfig;
  134. #pragma mark - User Interaction
  135. /**
  136. * 该bool值控制当pan View状态为long的情况下,是否可以继续拖拽到PanModalHeight = MAX的情况
  137. * 默认为YES,即当已经拖拽到long的情况下不能再继续拖动
  138. */
  139. - (BOOL)anchorModalToLongForm;
  140. /**
  141. * 是否允许点击背景处dismiss presented Controller
  142. * 默认为YES
  143. */
  144. - (BOOL)allowsTapBackgroundToDismiss;
  145. /**
  146. * 是否允许drag操作dismiss presented Controller
  147. * Default is YES
  148. */
  149. - (BOOL)allowsDragToDismiss;
  150. /// Default is YES, When return NO, and you did set shortForm, user CAN NOT pull down the view.
  151. - (BOOL)allowsPullDownWhenShortState;
  152. /**
  153. min Velocity from Vertical direction that trigger dismiss action.
  154. Default is 300.0
  155. */
  156. - (CGFloat)minVerticalVelocityToTriggerDismiss;
  157. /**
  158. * 是否允许用户操作
  159. * Default is YES
  160. */
  161. - (BOOL)isUserInteractionEnabled;
  162. /**
  163. * 是否允许触觉反馈
  164. * Default is YES
  165. */
  166. - (BOOL)isHapticFeedbackEnabled;
  167. /**
  168. * 是否允许触摸事件透传到presenting ViewController/View。如果你有特殊需求的话(比如弹出一个底部视图,但是你想操作弹出视图下面的view,即presenting VC/View),可开启此功能
  169. *
  170. * Whether allows touch events passing through the transition container view.
  171. * In some situations, you present the bottom VC/View, and you want to operate the presenting VC/View(mapView, scrollView and etc), enable this func.
  172. *
  173. * Note: You SHOULD MUST dismiss the presented VC in the right time.
  174. */
  175. - (BOOL)allowsTouchEventsPassingThroughTransitionView;
  176. #pragma mark - Screen left egde interaction
  177. /**
  178. * 是否允许屏幕边缘侧滑手势
  179. * Default is NO,not allowed this user interaction.
  180. *
  181. * Note: Currently only works on UIViewController.
  182. */
  183. - (BOOL)allowScreenEdgeInteractive;
  184. /**
  185. * Max allowed distance to screen left edge when you want to make screen edge pan interaction
  186. * Default is 0, means it will ignore this limit, full screen left edge pan will work.
  187. * @return distance to left screen edge
  188. */
  189. - (CGFloat)maxAllowedDistanceToLeftScreenEdgeForPanInteraction;
  190. /**
  191. * When you enabled `- (BOOL)allowScreenEdgeInteractive`, this can work.
  192. * min horizontal velocity to trigger screen edge dismiss if the drag didn't reach 0.5 screen width.
  193. * Default is 500
  194. */
  195. - (CGFloat)minHorizontalVelocityToTriggerScreenEdgeDismiss;
  196. #pragma mark - Customize presentingViewController animation
  197. /**
  198. * Config presentingViewController animation style, this animations will work for present & dismiss.
  199. * Default is `PresentingViewControllerAnimationStyleNone`.
  200. * @return The animation style.
  201. */
  202. - (PresentingViewControllerAnimationStyle)presentingVCAnimationStyle;
  203. /**
  204. * 自定义presenting ViewController转场动画,默认为nil
  205. * 注意:如果实现该方法并返回非空示例,要使该方法生效,`- (PresentingViewControllerAnimationStyle)presentingVCAnimationStyle`必须返回PresentingViewControllerAnimationStyleCustom
  206. *
  207. * custom presenting ViewController transition animation, default is nil
  208. * Note: If you implement this method and return non nil value, You must implement `- (PresentingViewControllerAnimationStyle)
  209. * presentingVCAnimationStyle` and return PresentingViewControllerAnimationStyleCustom
  210. */
  211. - (nullable id<HWPresentingViewControllerAnimatedTransitioning>)customPresentingVCAnimation;
  212. #pragma mark - Content UI config
  213. /**
  214. * 是否顶部圆角
  215. * Default is YES
  216. */
  217. - (BOOL)shouldRoundTopCorners;
  218. /**
  219. * 顶部圆角数值
  220. * Default is 8.0
  221. */
  222. - (CGFloat)cornerRadius;
  223. /**
  224. * presented content shadow
  225. * Default is None config
  226. */
  227. - (HWPanModalShadow *)contentShadow;
  228. #pragma mark - Indicator config
  229. /**
  230. * 是否显示drag指示view
  231. * Default is YES,Default this method depend on `- (BOOL)shouldRoundTopCorners`
  232. */
  233. - (BOOL)showDragIndicator;
  234. /**
  235. * You can make the indicator customized. Just adopt `HWPanModalIndicatorProtocol`
  236. * Default this method return nil, Then the default indicator will be used.
  237. */
  238. - (__kindof UIView<HWPanModalIndicatorProtocol> * _Nullable)customIndicatorView;
  239. #pragma mark - Keyboard handle
  240. /**
  241. * When there is text input view exists and becomeFirstResponder, will auto handle keyboard height.
  242. * Default is YES. You can disable it, handle it by yourself.
  243. */
  244. - (BOOL)isAutoHandleKeyboardEnabled;
  245. /**
  246. The offset that keyboard show from input view's bottom. It works when
  247. `isAutoHandleKeyboardEnabled` return YES.
  248. @return offset, default is 5.
  249. */
  250. - (CGFloat)keyboardOffsetFromInputView;
  251. #pragma mark - Delegate
  252. #pragma mark - Pan Gesture delegate
  253. /**
  254. * 询问delegate是否需要使拖拽手势生效
  255. * 若返回NO,则禁用拖拽手势操作,即不能拖拽dismiss
  256. * 默认为YES
  257. */
  258. - (BOOL)shouldRespondToPanModalGestureRecognizer:(nonnull UIPanGestureRecognizer *)panGestureRecognizer;
  259. /**
  260. * 当pan recognizer状态为begin/changed时,通知delegate回调。
  261. * 当拖动presented View时,该方法会持续的回调
  262. * 默认实现为空
  263. */
  264. - (void)willRespondToPanModalGestureRecognizer:(nonnull UIPanGestureRecognizer *)panGestureRecognizer;
  265. /**
  266. * 内部处理完成拖动操作后触发此回调,此时view frame可能已经变化。
  267. * Framework has did finish logic for GestureRecognizer delegate. It will call many times when you darg.
  268. */
  269. - (void)didRespondToPanModalGestureRecognizer:(nonnull UIPanGestureRecognizer *)panGestureRecognizer;
  270. /**
  271. * 内部处理完成拖动操作后触发此回调,此时view frame可能已经变化。
  272. * Framework has did finish logic for GestureRecognizer delegate. It will call many times when you darg.
  273. */
  274. - (void)didEndRespondToPanModalGestureRecognizer:(nonnull UIPanGestureRecognizer *)panGestureRecognizer;
  275. /**
  276. * 是否优先执行dismiss拖拽手势,当存在panScrollable的情况下,如果此方法返回YES,则
  277. * dismiss手势生效,scrollView本身的滑动则不再生效。也就是说可以拖动Controller view,而scrollView没法拖动了。
  278. *
  279. * 例子:controller view上添加一个TableView,并铺满全屏,然后在controller view 顶部添加一个一定大小的viewA,
  280. * 这个时候会发现viewA有时候无法拖动,可以实现此delegate方法来解决
  281. ```
  282. - (BOOL)shouldPrioritizePanModalGestureRecognizer:(UIPanGestureRecognizer *)panGestureRecognizer {
  283. CGPoint loc = [panGestureRecognizer locationInView:self.view];
  284. // check whether user pan action in viewA
  285. if (CGRectContainsPoint(self.viewA.frame, loc)) {
  286. return YES;
  287. }
  288. return NO;
  289. }
  290. ```
  291. * 默认为NO
  292. *
  293. * This delegate is useful when you want panGestureRecognizer has a high prioritize and
  294. * make scrollable does NOT scroll.
  295. * Example: You controller add a full size tableView, then add viewA on top of your controller view.
  296. * Now you find you can not drag the viewA, use this delegate to resolve problem.
  297. * Please refer to code above this comment.
  298. *
  299. * Default is NO
  300. */
  301. - (BOOL)shouldPrioritizePanModalGestureRecognizer:(nonnull UIPanGestureRecognizer *)panGestureRecognizer;
  302. /**
  303. * When you pan present controller to dismiss, and the view's y <= shortFormYPos,
  304. * this delegate method will be called.
  305. * @param percent 0 ~ 1, 1 means has dismissed
  306. */
  307. - (void)panModalGestureRecognizer:(nonnull UIPanGestureRecognizer *)panGestureRecognizer dismissPercent:(CGFloat)percent;
  308. #pragma mark - PresentationState change delegate
  309. /**
  310. * 是否应该变更panModal状态
  311. */
  312. - (BOOL)shouldTransitionToState:(PresentationState)state;
  313. /**
  314. * called when the Transition State will change.
  315. * 通知回调即将变更状态
  316. */
  317. - (void)willTransitionToState:(PresentationState)state;
  318. /**
  319. * PresentationState did change callback
  320. */
  321. - (void)didChangeTransitionToState:(PresentationState)state;
  322. #pragma mark - present delegate
  323. /**
  324. * call when present transition will begin.
  325. */
  326. - (void)panModalTransitionWillBegin;
  327. /**
  328. * call when present transition did finish.
  329. */
  330. - (void)panModalTransitionDidFinish;
  331. /**
  332. * call when your custom presented vc has been added to the presentation container.
  333. */
  334. - (void)presentedViewDidMoveToSuperView;
  335. #pragma mark - Dismiss delegate
  336. /**
  337. * will dismiss
  338. */
  339. - (void)panModalWillDismiss;
  340. /**
  341. * Did finish dismissing
  342. */
  343. - (void)panModalDidDismissed;
  344. #pragma mark - DEPRECATED DECLARE
  345. /**
  346. * 是否对presentingViewController做动画效果,默认该效果类似淘宝/京东购物车凹陷效果
  347. * 默认为NO
  348. */
  349. - (BOOL)shouldAnimatePresentingVC DEPRECATED_MSG_ATTRIBUTE("This api has been marked as DEPRECATED on version 0.3.6, please use `- (PresentingViewControllerAnimationStyle)presentingVCAnimationStyle` replaced.");
  350. /**
  351. * 背景透明度
  352. * Default is 0.7
  353. */
  354. - (CGFloat)backgroundAlpha DEPRECATED_MSG_ATTRIBUTE("This api has been marked as DEPRECATED on version 0.7.0, please use `- (HWBackgroundConfig *)backgroundConfig` replaced.");
  355. /**
  356. * Blur background
  357. * This function can NOT coexist with backgroundAlpha
  358. * Default use backgroundAlpha, Once you set backgroundBlurRadius > 0, blur will work.
  359. * Recommend set the value 10 ~ 20.
  360. * @return blur radius
  361. */
  362. - (CGFloat)backgroundBlurRadius DEPRECATED_MSG_ATTRIBUTE("This api has been marked as DEPRECATED on version 0.7.0, please use `- (HWBackgroundConfig *)backgroundConfig` replaced.");
  363. /**
  364. * blur background color
  365. * @return color, default is White Color.
  366. */
  367. - (nonnull UIColor *)backgroundBlurColor DEPRECATED_MSG_ATTRIBUTE("This api has been marked as DEPRECATED on version 0.7.0, please use `- (HWBackgroundConfig *)backgroundConfig` replaced.");
  368. @end
  369. NS_ASSUME_NONNULL_END