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
UIViewController
to present. - Support View which inherit from
HWPanModalContentView
to 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
blur
background. 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.6.0'
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);
}
@end
Where 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.
Objective-C
& Swift
Examples , for most of the framework functions.
I have wrote both pure Contact Me
Heath Wang yishu.jay@gmail.com
Change Log
License
HWPanModal is released under a MIT License. See LICENSE file for details.