{"id":15026265,"url":"https://github.com/heathwang/hwpanmodal","last_synced_at":"2025-05-15T17:04:16.771Z","repository":{"id":34881435,"uuid":"184992407","full_name":"HeathWang/HWPanModal","owner":"HeathWang","description":"HWPanModal presents controller from bottom and drag to dismiss, high customize. iOS13 default modalPresentationStyle. 任意形式的底部弹框动画；头条、知乎、抖音弹出评论效果；地图浮层，iOS13 present默认模态效果。","archived":false,"fork":false,"pushed_at":"2024-05-30T08:29:09.000Z","size":17700,"stargazers_count":1192,"open_issues_count":12,"forks_count":203,"subscribers_count":19,"default_branch":"master","last_synced_at":"2025-05-03T17:43:45.030Z","etag":null,"topics":["animation","bottomsheet","card-animation","drag-drop","gesture-control","ios-ui","ios13","modalpresentationstyle","panmodal","popup","presenter","sheet"],"latest_commit_sha":null,"homepage":"","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HeathWang.png","metadata":{"files":{"readme":"README-CN.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":"Supporting Files/Info.plist","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-05T06:59:25.000Z","updated_at":"2025-04-24T17:08:10.000Z","dependencies_parsed_at":"2022-08-08T09:15:12.345Z","dependency_job_id":"314fcebd-a4a3-4090-9bc5-8d286ce53f45","html_url":"https://github.com/HeathWang/HWPanModal","commit_stats":{"total_commits":298,"total_committers":9,"mean_commits":"33.111111111111114","dds":0.1476510067114094,"last_synced_commit":"0127f29a5287b73dba357ad8e989315a5b92b7ec"},"previous_names":[],"tags_count":82,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HeathWang%2FHWPanModal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HeathWang%2FHWPanModal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HeathWang%2FHWPanModal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HeathWang%2FHWPanModal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HeathWang","download_url":"https://codeload.github.com/HeathWang/HWPanModal/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254384987,"owners_count":22062422,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","bottomsheet","card-animation","drag-drop","gesture-control","ios-ui","ios13","modalpresentationstyle","panmodal","popup","presenter","sheet"],"created_at":"2024-09-24T20:04:10.117Z","updated_at":"2025-05-15T17:04:16.752Z","avatar_url":"https://github.com/HeathWang.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# HWPanModal 👍\n\u003cp style=\"align: left\"\u003e\n    \u003ca href=\"https://cocoapods.org/pods/HWPanModal\"\u003e\n       \u003cimg src=\"https://img.shields.io/cocoapods/v/HWPanModal.svg?style=flat\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://cocoapods.org/pods/HWPanModal\"\u003e\n       \u003cimg src=\"https://img.shields.io/cocoapods/p/HWPanModal.svg?style=flat\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://cocoapods.org/pods/HWPanModal\"\u003e\n       \u003cimg src=\"https://img.shields.io/badge/support-ios%208%2B-orange.svg\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://cocoapods.org/pods/HWPanModal\"\u003e\n       \u003cimg src=\"https://img.shields.io/badge/language-objective--c-blue.svg\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://travis-ci.org/HeathWang/HWPanModal\"\u003e\n       \u003cimg src=\"https://travis-ci.org/HeathWang/HWPanModal.svg?branch=master\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://codebeat.co/projects/github-com-heathwang-hwpanmodal-master\"\u003e\n        \u003cimg alt=\"codebeat badge\" src=\"https://codebeat.co/badges/fb96e7ea-2320-4219-8f19-777674a97d0e\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n\nHWPanModal 用于从底部弹出控制器（UIViewController），并用拖拽手势来关闭控制器。提供了自定义视图大小和位置，高度自定义弹出视图的各个属性。\n\nAPP中常见的从底部弹出视图，可以通过该框架快速实现，只需专注于相应的视图编写。常规热门app的UI示例：\n1. 知乎APP的查看评论\n2. 抖音的评论查看\n3. 微信，网易音乐等app弹出分享\n4. 嘀嗒出行行程进行页（地图上的浮层view效果）\n5. iOS13 默认模态(present)效果\n6. And more...\n\n## 截图\n\n\u003cdiv style=\"text-align: center\"\u003e\n    \u003ctable\u003e\n        \u003ctr\u003e\n            \u003cth\u003eBasic\u003c/th\u003e\n            \u003cth\u003eBlur background\u003c/th\u003e\n            \u003cth\u003eKeyboard handle\u003c/th\u003e\n            \u003cth\u003eApp demo\u003c/th\u003e          \n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd style=\"text-align: center\"\u003e\n            \u003cimg src=\"images/HWPanModal_example.gif\" width=\"180\" /\u003e\n            \u003c/td\u003e\n            \u003ctd style=\"text-align: center\"\u003e\n            \u003cimg src=\"images/HWPanModal_example_3.gif\" width=\"180\"/\u003e\n            \u003c/td\u003e\n            \u003ctd style=\"text-align: center\"\u003e\n            \u003cimg src=\"images/HWPanModal_example_4.gif\" width=\"180\"/\u003e\n            \u003c/td\u003e\n            \u003ctd style=\"text-align: center\"\u003e\n            \u003cimg src=\"images/HWPanModal_example_2.gif\" width=\"180\"/\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/table\u003e\n\u003c/div\u003e\n\n## 功能\n1. 支持任意类型的 `UIViewController`\n2. 支持继承自 `HWPanModalContentView` 的view\n3. 平滑的转场动画\n4. 支持2种类型的手势dismiss视图\n    1. 上下方向拖动关闭视图。\n    2. 侧滑关闭视图，支持全屏侧滑。\n5. 支持为presenting VC编写自定义动画。\n6. 支持配置动画时间，动画options，弹性spring值\n7. 支持配置背景alpha，或者高斯模糊背景。注意：动态调整模糊效果仅工作于iOS9.0+。\n8. 支持显示隐藏指示器，修改圆角\n9. 自动处理键盘弹出消失事件。\n10. 自定义指示器indicator view。\n11. 事件可以穿透到下层presenting VC。\n12. 可配置presented content 阴影。\n\n更多配置信息请参阅 [_HWPanModalPresentable.h_](https://github.com/HeathWang/HWPanModal/blob/master/Sources/Presentable/HWPanModalPresentable.h) 声明。\n\n## 特别注意\n\n1. 任何情况下，内部嵌套scrollable（UIScrollView，UITableView，UIWebView，UICollectionView），如果scrollable的contentSize变化了，务必调用`- (void)hw_panModalSetNeedsLayoutUpdate`刷新UI！！！\n2. 如果需要弹出浮层后push到下一层，使用`HWPanModalContentView`或者present vc用navigation 包一层。\n3. 请仔细阅读md，编译run示例代码，95%的功能在示例中都有展示，不要什么都不看就来问问题！！！\n\n\n### 支持UIViewController和继承自HWPanModalContentView弹出视图\n\n从0.6.0版本后, 该框架支持使用 `HWPanModalContentView` 从底部弹出视图, 即实现了present ViewController同样的交互和动画。\n\n不同点是 `HWPanModalContentView` 只是一个view视图, 通过添加一些动画实现了原本的功能。不像present ViewController的模式，你可以获得controller的整个生命周期，并且可以使用navigation栈来push VC。\n\n`HWPanModalContentView` 目前的限制:\n* 不支持转屏。\n* 不支持屏幕边缘横向拖拽来dismiss。\n* 不支持自定义presenting VC动画。（因为是view，没有presenting VC）\n\n    \n## 适配\n**iOS 8.0+**, support Objective-C \u0026 Swift.\n\n## 安装\n\n### [CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html)\n\n```ruby\npod 'HWPanModal', '~\u003e 0.9.9'\n```\n\n## 如何使用\n\n### 如何从底部弹出控制器\n只需要视图控制器适配 `HWPanModalPresentable` 协议即可. 默认情况下，不用重写适配的各个方法，如果需要自定义，请实现协议方法。\n\n更多的自定义UI配置，请参见`HWPanModalPresentable`协议中每个方法的说明。\n\n```Objective-C\n#import \u003cHWPanModal/HWPanModal.h\u003e\n@interface HWBaseViewController () \u003cHWPanModalPresentable\u003e\n\n@end\n\n@implementation HWBaseViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    // Do any additional setup after loading the view.\n}\n\n#pragma mark - HWPanModalPresentable\n- (PanModalHeight)longFormHeight {\n    return PanModalHeightMake(PanModalHeightTypeMaxTopInset, 44);\n}\n@end\n```\n\n弹出控制器：\n\n```Objective-C\n#import \u003cHWPanModal/HWPanModal.h\u003e\n[self presentPanModal:[HWBaseViewController new]];\n```\n\n就是这么简单。\n\n### 如何主动更新控制器UI\n请查阅 `UIViewController+Presentation.h`，里面有详细说明。\n* Change the state between short and long form. call `- (void)hw_panModalTransitionTo:(PresentationState)state;`\n* Change ScrollView ContentOffset. call `- (void)hw_panModalSetContentOffset:(CGPoint)offset;`\n* Reload layout. call `- (void)hw_panModalSetNeedsLayoutUpdate;`\n    * 注意：如果scrollable view的contentSize改变了，你必须调用改reload方法来更新UI。\n\n### 自定义presenting VC动画编写\n\n1. Create object conforms `HWPresentingViewControllerAnimatedTransitioning` .\n\n    ```Objective-C\n    \n    @interface HWMyCustomAnimation : NSObject \u003cHWPresentingViewControllerAnimatedTransitioning\u003e\n    \n    @end\n    \n    @implementation HWMyCustomAnimation\n    \n    \n    - (void)presentAnimateTransition:(id\u003cHWPresentingViewControllerContextTransitioning\u003e)transitionContext {\n        NSTimeInterval duration = [transitionContext transitionDuration];\n        UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];\n        // replace it.\n        [UIView animateWithDuration:duration delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{\n            fromVC.view.transform = CGAffineTransformMakeScale(0.95, 0.95);\n        } completion:^(BOOL finished) {\n            \n        }];\n    }\n    \n    - (void)dismissAnimateTransition:(id\u003cHWPresentingViewControllerContextTransitioning\u003e)transitionContext {\n        NSTimeInterval duration = [transitionContext transitionDuration];\n        UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];\n        // replace it.\n        [UIView animateWithDuration:duration animations:^{\n            toVC.view.transform = CGAffineTransformIdentity;\n        }];\n    }\n    \n    @end\n    ```\n1. Overwrite below two method.\n\n    ```Objective-C\n    - (PresentingViewControllerAnimationStyle)presentingVCAnimationStyle {\n        return PresentingViewControllerAnimationStyleCustom;\n    }\n    \n    - (id\u003cHWPresentingViewControllerAnimatedTransitioning\u003e)customPresentingVCAnimation {\n        return self.customAnimation;\n    }\n    \n    - (HWMyCustomAnimation *)customAnimation {\n        if (!_customAnimation) {\n            _customAnimation = [HWMyCustomAnimation new];\n        }\n        return _customAnimation;\n    }\n    ```\n    \n### 自定义指示器indicator view\n\nYou just need to create your own UIView, then adopt `HWPanModalIndicatorProtocol`.\n\nIn your presented controller, return it:\n\n```Objective-C\n- (nullable UIView \u003cHWPanModalIndicatorProtocol\u003e *)customIndicatorView {\n    HWTextIndicatorView *textIndicatorView = [HWTextIndicatorView new];\n    return textIndicatorView;\n}\n```\n\nHere is `HWTextIndicatorView` code:\n\n```Objective-C\n@interface HWTextIndicatorView : UIView \u003cHWPanModalIndicatorProtocol\u003e\n\n@end\n\n@interface HWTextIndicatorView ()\n@property (nonatomic, strong) UILabel *stateLabel;\n@end\n\n@implementation HWTextIndicatorView\n\n- (instancetype)initWithFrame:(CGRect)frame {\n    self = [super initWithFrame:frame];\n    if (self) {\n        // init the _stateLabel\n        [self addSubview:_stateLabel];\n    }\n    return self;\n}\n\n\n- (void)didChangeToState:(HWIndicatorState)state {\n    switch (state) {\n        case HWIndicatorStateNormal: {\n            self.stateLabel.text = @\"Please pull down to dismiss\";\n            self.stateLabel.textColor = [UIColor whiteColor];\n        }\n            break;\n        case HWIndicatorStatePullDown: {\n            self.stateLabel.text = @\"Keep pull down to dismiss\";\n            self.stateLabel.textColor = [UIColor colorWithRed:1.000 green:0.200 blue:0.000 alpha:1.00];\n        }\n            break;\n    }\n}\n\n- (CGSize)indicatorSize {\n    return CGSizeMake(200, 18);\n}\n\n- (void)setupSubviews {\n    self.stateLabel.frame = self.bounds;\n}\n\n@end\n\n```   \n\n### 如何使用HWPanModalContentView\n\n你必须继承自 `HWPanModalContentView`. `HWPanModalContentView` 适配 `HWPanModalPresentable` 协议，就像你可用该协议来present一样。\n\n```Objective-C\n@interface HWSimplePanModalView : HWPanModalContentView\n\n@end\n\n@implementation HWSimplePanModalView\n\n- (instancetype)initWithFrame:(CGRect)frame {\n    self = [super initWithFrame:frame];\n    if (self) {\n        // add view and layout.\n    }\n    \n    return self;\n}\n\n// present it.\nHWSimplePanModalView *simplePanModalView = [HWSimplePanModalView new];\n[simplePanModalView presentInView:nil];\n```\n \n\n## 例子\n\n1. 克隆项目\n2. 然后执行 `pod install`\n3. 打开 HWPanModal.xcworkspace, 选择OC或者Swift项目运行\n\n###### 我分别编写了纯`Objective-C` \u0026 `Swift`例子，基本涵盖了该framework的所有API使用。\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=HeathWang/HWPanModal\u0026type=Date)](https://star-history.com/#HeathWang/HWPanModal\u0026Date)\n\n## 联系我\n\nHeath Wang\nyishu.jay@gmail.com\n\n## WX\n\n\u003cp style=\"align: left\"\u003e\n    \u003ca\u003e\n       \u003cimg src=\"images/groupChat.jpg\" width=\"277\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n## License\n\n\u003cb\u003eHWPanModal\u003c/b\u003e is released under a MIT License. See LICENSE file for details.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheathwang%2Fhwpanmodal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fheathwang%2Fhwpanmodal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheathwang%2Fhwpanmodal/lists"}