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 to JetBrains! I use AppCode IDE to develop my open source project.
- 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.
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).
- 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.
iOS 8.0+, support Objective-C & Swift.
pod 'HWPanModal', '~> 0.9.4'
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.
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.
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; }
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
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];
- Clone this git.
- open the terminal, run
pod install
- Double click HWPanModal.xcworkspace, and select a target to run.
Heath Wang yishu.jay@gmail.com
HWPanModal is released under a MIT License. See LICENSE file for details.