HWPanModal π
HWPanModal is used to present controller and drag to dismiss. Similar with iOS13 default present Modal style.
Inspired by PanModal, thanks.
My another project for pop controller:HWPopController
Special Thanks
Special Thanks to JetBrains! I use AppCode IDE to develop my open source project.
Snapshoot
Index
Features
- Supports any type of
UIViewControllerto present. - Support View which inherit from
HWPanModalContentViewto present. - Seamless transition between modal and content.
- Support two kinds of dismissal gestureRecognizer interaction
- Pan gesture direction up&down
- Pan gesture direction right, you can swipe on screen edge to dismiss controller.
- Support write your own animation for presenting VC.
- Support config animation
Duration,AnimationOptions,springDamping. - Support config background alpha or
blurbackground. Note: Dynamic change blur effect ONLY works on iOS9.0+. - Show / hide corner, indicator.
- Auto handle UIKeyboard show/hide.
- Hight customize indicator view.
- Touch event response can pass through to presenting VC.
- Config presented view shadow style.
More config pls see HWPanModalPresentable.h declare.
What's different between UIViewController and HWPanModalContentView to present ?
From version 0.6.0, this framework support using HWPanModalContentView to present from bottom, that means we can add subview(inherit from HWPanModalContentView) to the target view that you want to show.
The different is HWPanModalContentView is just a view, and support some animations, unlike present ViewController, you will got ViewController life circle, and navigation stack.
HWPanModalContentView limit:
- Currently not support screen rotation.
- Not support edge horizontal pan to dismiss.
- Not support customize presentingVC animation. (There is no presentingVC for view).
TODO
- Handle keyboard show&dismiss.
- High customize indicator view.
- Edge Interactive dismissal can work on full screen and configable distance to left edge.
- Touch event can response to presenting VC, working on it.
- Strip the presented view container view, make it can use directly.
Compatibility
iOS 8.0+, support Objective-C & Swift.
Installation
CocoaPods
pod 'HWPanModal', '~> 0.9.4'How to use
How to present UIViewController from bottom
Your UIViewController need to conform HWPanModalPresentable. If you use default, nothing more will be written.
#import <HWPanModal/HWPanModal.h>
@interface HWBaseViewController () <HWPanModalPresentable>
@end
@implementation HWBaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
#pragma mark - HWPanModalPresentable
- (PanModalHeight)longFormHeight {
return PanModalHeightMake(PanModalHeightTypeMaxTopInset, 44);
}
@endWhere you need to present this Controller.
#import <HWPanModal/HWPanModal.h>
[self presentPanModal:[HWBaseViewController new]];yeah! Easy.
Change state, scrollView contentOffset, reload layout. IMPORTANT!
When You present you Controller, you can change the UI.
Refer to UIViewController+Presentation.h.
- Change the state between short and long form. call
- (void)hw_panModalTransitionTo:(PresentationState)state; - Change ScrollView ContentOffset. call
- (void)hw_panModalSetContentOffset:(CGPoint)offset; - Reload layout. call
- (void)hw_panModalSetNeedsLayoutUpdate;- Note: When your scrollable changed it's contentSize, you MUST reload the layout.
Custom Presenting VC Animation
Some guys want to animate Presenting VC when present/dismiss.
-
Create object conforms
HWPresentingViewControllerAnimatedTransitioning.@interface HWMyCustomAnimation : NSObject <HWPresentingViewControllerAnimatedTransitioning> @end @implementation HWMyCustomAnimation - (void)presentAnimateTransition:(id<HWPresentingViewControllerContextTransitioning>)transitionContext { NSTimeInterval duration = [transitionContext transitionDuration]; UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; // replace it. [UIView animateWithDuration:duration delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ fromVC.view.transform = CGAffineTransformMakeScale(0.95, 0.95); } completion:^(BOOL finished) { }]; } - (void)dismissAnimateTransition:(id<HWPresentingViewControllerContextTransitioning>)transitionContext { // no need for using animating block. UIViewController *toVC = [context viewControllerForKey:UITransitionContextToViewControllerKey]; toVC.view.transform = CGAffineTransformIdentity; } @end
-
Overwrite below two method.
- (PresentingViewControllerAnimationStyle)presentingVCAnimationStyle { return PresentingViewControllerAnimationStyleCustom; } - (id<HWPresentingViewControllerAnimatedTransitioning>)customPresentingVCAnimation { return self.customAnimation; } - (HWMyCustomAnimation *)customAnimation { if (!_customAnimation) { _customAnimation = [HWMyCustomAnimation new]; } return _customAnimation; }
Custom your own indicator view
You just need to create your own UIView, then adopt HWPanModalIndicatorProtocol.
In your presented controller, return it:
- (nullable UIView <HWPanModalIndicatorProtocol> *)customIndicatorView {
HWTextIndicatorView *textIndicatorView = [HWTextIndicatorView new];
return textIndicatorView;
}Here is HWTextIndicatorView code:
@interface HWTextIndicatorView : UIView <HWPanModalIndicatorProtocol>
@end
@interface HWTextIndicatorView ()
@property (nonatomic, strong) UILabel *stateLabel;
@end
@implementation HWTextIndicatorView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// init the _stateLabel
[self addSubview:_stateLabel];
}
return self;
}
- (void)didChangeToState:(HWIndicatorState)state {
switch (state) {
case HWIndicatorStateNormal: {
self.stateLabel.text = @"Please pull down to dismiss";
self.stateLabel.textColor = [UIColor whiteColor];
}
break;
case HWIndicatorStatePullDown: {
self.stateLabel.text = @"Keep pull down to dismiss";
self.stateLabel.textColor = [UIColor colorWithRed:1.000 green:0.200 blue:0.000 alpha:1.00];
}
break;
}
}
- (CGSize)indicatorSize {
return CGSizeMake(200, 18);
}
- (void)setupSubviews {
self.stateLabel.frame = self.bounds;
}
@end
How to use HWPanModalContentView
You should always inherit from HWPanModalContentView. HWPanModalContentView conforms HWPanModalPresentable like the way using UIViewController.
@interface HWSimplePanModalView : HWPanModalContentView
@end
@implementation HWSimplePanModalView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// add view and layout.
}
return self;
}
// present it.
HWSimplePanModalView *simplePanModalView = [HWSimplePanModalView new];
[simplePanModalView presentInView:nil];Example
- Clone this git.
- open the terminal, run
pod install - Double click HWPanModal.xcworkspace, and select a target to run.
I have wrote both pure Objective-C & SwiftExamples , for most of the framework functions.
Contact Me
Heath Wang [email protected]
Change Log
License
HWPanModal is released under a MIT License. See LICENSE file for details.




