提交
This commit is contained in:
21
Pods/HWPopController/HWPopController/Classes/Animator/HWDefaultPopAnimator.h
generated
Executable file
21
Pods/HWPopController/HWPopController/Classes/Animator/HWDefaultPopAnimator.h
generated
Executable file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// HWDefaultPopAnimator.h
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/22.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <HWPopController/HWPopControllerAnimationProtocol.h>
|
||||
#import <HWPopController/HWPopController.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HWDefaultPopAnimator : NSObject <HWPopControllerAnimationProtocol>
|
||||
|
||||
@property (nonatomic, assign) HWPopType popType;
|
||||
@property (nonatomic, assign) HWDismissType dismissType;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
301
Pods/HWPopController/HWPopController/Classes/Animator/HWDefaultPopAnimator.m
generated
Executable file
301
Pods/HWPopController/HWPopController/Classes/Animator/HWDefaultPopAnimator.m
generated
Executable file
@@ -0,0 +1,301 @@
|
||||
//
|
||||
// HWDefaultPopAnimator.m
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/22.
|
||||
//
|
||||
|
||||
#import "HWDefaultPopAnimator.h"
|
||||
#import "HWPopControllerAnimatedTransitioning.h"
|
||||
|
||||
static const CGFloat kDefaultSpringDamping = 0.8;
|
||||
static const CGFloat kDefaultSpringVelocity = 10.0;
|
||||
|
||||
@implementation HWDefaultPopAnimator
|
||||
|
||||
- (NSTimeInterval)popControllerAnimationDuration:(HWPopAnimationContext *)context {
|
||||
return context.duration ?: 0.2;
|
||||
}
|
||||
|
||||
- (void)popAnimate:(HWPopAnimationContext *)context completion:(void (^)(BOOL finished))completion {
|
||||
NSTimeInterval duration = [self popControllerAnimationDuration:context];
|
||||
UIView *containerView = context.containerView;
|
||||
switch (self.popType) {
|
||||
case HWPopTypeFadeIn:{
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
containerView.alpha = 0;
|
||||
[UIView animateWithDuration:duration animations:^{
|
||||
containerView.alpha = 1;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWPopTypeGrowIn:{
|
||||
containerView.transform = CGAffineTransformMakeScale(0.9, 0.9);
|
||||
containerView.alpha = 0;
|
||||
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
containerView.alpha = 1;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWPopTypeShrinkIn:{
|
||||
containerView.alpha = 0;
|
||||
containerView.transform = CGAffineTransformMakeScale(1.1, 1.1);
|
||||
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
containerView.alpha = 1;
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWPopTypeSlideInFromTop:{
|
||||
containerView.alpha = 1;
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
CGRect originFrame = containerView.frame;
|
||||
CGRect rect = containerView.frame;
|
||||
rect.origin.y = -CGRectGetHeight(originFrame) - 20;
|
||||
containerView.frame = rect;
|
||||
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
containerView.frame = originFrame;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWPopTypeSlideInFromBottom:{
|
||||
containerView.alpha = 1;
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
CGRect originFrame = containerView.frame;
|
||||
CGRect rect = containerView.frame;
|
||||
rect.origin.y = containerView.superview.frame.size.height;
|
||||
containerView.frame = rect;
|
||||
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
containerView.frame = originFrame;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWPopTypeSlideInFromLeft:{
|
||||
containerView.alpha = 1;
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
CGRect originFrame = containerView.frame;
|
||||
CGRect rect = containerView.frame;
|
||||
rect.origin.x = -CGRectGetWidth(rect);
|
||||
containerView.frame = rect;
|
||||
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
containerView.frame = originFrame;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWPopTypeSlideInFromRight:{
|
||||
containerView.alpha = 1;
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
CGRect originFrame = containerView.frame;
|
||||
CGRect rect = containerView.frame;
|
||||
rect.origin.x = CGRectGetWidth(containerView.superview.frame);
|
||||
containerView.frame = rect;
|
||||
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
containerView.frame = originFrame;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWPopTypeBounceIn:{
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
containerView.alpha = 0;
|
||||
containerView.transform = CGAffineTransformMakeScale(0.1, 0.1);
|
||||
[UIView animateWithDuration:duration delay:0 usingSpringWithDamping:kDefaultSpringDamping initialSpringVelocity:kDefaultSpringVelocity options:0 animations:^{
|
||||
containerView.alpha = 1;
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWPopTypeBounceInFromTop:{
|
||||
containerView.alpha = 1;
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
CGRect originFrame = containerView.frame;
|
||||
CGRect rect = containerView.frame;
|
||||
rect.origin.y = -CGRectGetHeight(originFrame);
|
||||
containerView.frame = rect;
|
||||
[UIView animateWithDuration:duration delay:0 usingSpringWithDamping:kDefaultSpringDamping initialSpringVelocity:kDefaultSpringVelocity options:0 animations:^{
|
||||
containerView.frame = originFrame;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWPopTypeBounceInFromBottom:{
|
||||
containerView.alpha = 1;
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
CGRect originFrame = containerView.frame;
|
||||
CGRect rect = containerView.frame;
|
||||
rect.origin.y = CGRectGetHeight(containerView.superview.frame);
|
||||
containerView.frame = rect;
|
||||
[UIView animateWithDuration:duration delay:0 usingSpringWithDamping:kDefaultSpringDamping initialSpringVelocity:kDefaultSpringVelocity options:0 animations:^{
|
||||
containerView.frame = originFrame;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWPopTypeBounceInFromLeft:{
|
||||
containerView.alpha = 1;
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
CGRect originFrame = containerView.frame;
|
||||
CGRect rect = containerView.frame;
|
||||
rect.origin.x = -CGRectGetWidth(rect);
|
||||
containerView.frame = rect;
|
||||
[UIView animateWithDuration:duration delay:0 usingSpringWithDamping:kDefaultSpringDamping initialSpringVelocity:kDefaultSpringVelocity options:0 animations:^{
|
||||
containerView.frame = originFrame;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWPopTypeBounceInFromRight:{
|
||||
containerView.alpha = 1;
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
CGRect originFrame = containerView.frame;
|
||||
CGRect rect = containerView.frame;
|
||||
rect.origin.x = CGRectGetWidth(containerView.superview.frame);
|
||||
containerView.frame = rect;
|
||||
[UIView animateWithDuration:duration delay:0 usingSpringWithDamping:kDefaultSpringDamping initialSpringVelocity:kDefaultSpringVelocity options:0 animations:^{
|
||||
containerView.frame = originFrame;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
default:{
|
||||
containerView.alpha = 1;
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
completion ? completion(YES) : nil;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dismissAnimate:(HWPopAnimationContext *)context completion:(void (^)(BOOL finished))completion {
|
||||
NSTimeInterval duration = [self popControllerAnimationDuration:context];
|
||||
NSTimeInterval bounceDuration1 = duration * 1.f / 3.f;
|
||||
NSTimeInterval bounceDuration2 = duration * 2.f / 3.f;
|
||||
|
||||
UIView *containerView = context.containerView;
|
||||
switch (self.dismissType) {
|
||||
case HWDismissTypeFadeOut:{
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
[UIView animateWithDuration:duration animations:^{
|
||||
containerView.alpha = 0;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWDismissTypeGrowOut:{
|
||||
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
containerView.transform = CGAffineTransformMakeScale(1.1, 1.1);
|
||||
containerView.alpha = 0;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWDismissTypeShrinkOut:{
|
||||
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
containerView.alpha = 0;
|
||||
containerView.transform = CGAffineTransformMakeScale(0.85, 0.85);
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWDismissTypeSlideOutToTop:{
|
||||
CGRect rect = containerView.frame;
|
||||
rect.origin.y = -CGRectGetHeight(rect);
|
||||
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
containerView.frame = rect;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWDismissTypeSlideOutToBottom:{
|
||||
CGRect rect = containerView.frame;
|
||||
rect.origin.y = containerView.superview.frame.size.height;
|
||||
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
containerView.frame = rect;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWDismissTypeSlideOutToLeft:{
|
||||
CGRect rect = containerView.frame;
|
||||
rect.origin.x = -CGRectGetWidth(rect);
|
||||
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
containerView.frame = rect;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWDismissTypeSlideOutToRight:{
|
||||
CGRect rect = containerView.frame;
|
||||
rect.origin.x = CGRectGetWidth(containerView.superview.frame);
|
||||
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
containerView.frame = rect;
|
||||
} completion:completion];
|
||||
}
|
||||
break;
|
||||
case HWDismissTypeBounceOut:{
|
||||
[UIView animateWithDuration:bounceDuration1 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
|
||||
containerView.transform = CGAffineTransformMakeScale(1.1, 1.1);
|
||||
} completion:^(BOOL finished) {
|
||||
[UIView animateWithDuration:bounceDuration2 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
|
||||
containerView.alpha = 0;
|
||||
containerView.transform = CGAffineTransformMakeScale(0.1, 0.1);
|
||||
} completion:completion];
|
||||
}];
|
||||
}
|
||||
break;
|
||||
case HWDismissTypeBounceOutToTop:{
|
||||
CGRect rect1 = containerView.frame;
|
||||
rect1.origin.y += 20;
|
||||
CGRect rect2 = containerView.frame;
|
||||
rect2.origin.y = -CGRectGetHeight(rect2);
|
||||
[UIView animateWithDuration:bounceDuration1 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
|
||||
containerView.frame = rect1;
|
||||
} completion:^(BOOL finished) {
|
||||
[UIView animateWithDuration:bounceDuration2 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
|
||||
containerView.frame = rect2;
|
||||
} completion:completion];
|
||||
}];
|
||||
}
|
||||
break;
|
||||
case HWDismissTypeBounceOutToBottom:{
|
||||
CGRect rect1 = containerView.frame;
|
||||
rect1.origin.y -= 20;
|
||||
CGRect rect2 = containerView.frame;
|
||||
rect2.origin.y = CGRectGetHeight(containerView.superview.frame);
|
||||
[UIView animateWithDuration:bounceDuration1 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
|
||||
containerView.frame = rect1;
|
||||
} completion:^(BOOL finished) {
|
||||
[UIView animateWithDuration:bounceDuration2 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
|
||||
containerView.frame = rect2;
|
||||
} completion:completion];
|
||||
}];
|
||||
}
|
||||
break;
|
||||
case HWDismissTypeBounceOutToLeft:{
|
||||
CGRect rect1 = containerView.frame;
|
||||
rect1.origin.x += 20;
|
||||
CGRect rect2 = containerView.frame;
|
||||
rect2.origin.x = -CGRectGetWidth(rect2);
|
||||
[UIView animateWithDuration:bounceDuration1 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
|
||||
containerView.frame = rect1;
|
||||
} completion:^(BOOL finished) {
|
||||
[UIView animateWithDuration:bounceDuration2 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
|
||||
containerView.frame = rect2;
|
||||
} completion:completion];
|
||||
}];
|
||||
}
|
||||
break;
|
||||
case HWDismissTypeBounceOutToRight:{
|
||||
CGRect rect1 = containerView.frame;
|
||||
rect1.origin.x -= 20;
|
||||
CGRect rect2 = containerView.frame;
|
||||
rect2.origin.x = CGRectGetWidth(containerView.superview.frame);
|
||||
[UIView animateWithDuration:bounceDuration1 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
|
||||
containerView.frame = rect1;
|
||||
} completion:^(BOOL finished) {
|
||||
[UIView animateWithDuration:bounceDuration2 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
|
||||
containerView.frame = rect2;
|
||||
} completion:completion];
|
||||
}];
|
||||
}
|
||||
break;
|
||||
default:{
|
||||
containerView.alpha = 0;
|
||||
containerView.transform = CGAffineTransformIdentity;
|
||||
completion ? completion(YES) : nil;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
29
Pods/HWPopController/HWPopController/Classes/Animator/HWNavAnimatedTransitioning.h
generated
Executable file
29
Pods/HWPopController/HWPopController/Classes/Animator/HWNavAnimatedTransitioning.h
generated
Executable file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// HWNavAnimatedTransitioning.h
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/6/10.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <HWPopController/HWPopController.h>
|
||||
|
||||
@class HWNavAnimatedTransitioning;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
|
||||
@interface HWNavAnimatedTransitioning : NSObject <UIViewControllerAnimatedTransitioning>
|
||||
|
||||
@property (nonatomic, assign) HWPopState state;
|
||||
|
||||
- (instancetype)initWithState:(HWPopState)state NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
54
Pods/HWPopController/HWPopController/Classes/Animator/HWNavAnimatedTransitioning.m
generated
Executable file
54
Pods/HWPopController/HWPopController/Classes/Animator/HWNavAnimatedTransitioning.m
generated
Executable file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// HWNavAnimatedTransitioning.m
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/6/10.
|
||||
//
|
||||
|
||||
#import "HWNavAnimatedTransitioning.h"
|
||||
|
||||
@implementation HWNavAnimatedTransitioning
|
||||
|
||||
- (instancetype)initWithState:(HWPopState)state {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_state = state;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - UIViewControllerAnimatedTransitioning
|
||||
|
||||
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext {
|
||||
return 0.15;
|
||||
}
|
||||
|
||||
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
|
||||
|
||||
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
|
||||
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
|
||||
|
||||
if (self.state == HWPopStatePop) {
|
||||
CGRect f = [transitionContext finalFrameForViewController:toVC];
|
||||
toVC.view.frame = f;
|
||||
[transitionContext.containerView insertSubview:toVC.view aboveSubview:fromVC.view];
|
||||
} else {
|
||||
[transitionContext.containerView insertSubview:toVC.view belowSubview:fromVC.view];
|
||||
}
|
||||
|
||||
fromVC.view.alpha = 1;
|
||||
toVC.view.alpha = 0;
|
||||
|
||||
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
|
||||
fromVC.view.alpha = 0;
|
||||
toVC.view.alpha = 1;
|
||||
} completion:^(BOOL finished) {
|
||||
[transitionContext completeTransition:YES];
|
||||
|
||||
fromVC.view.alpha = 1;
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
35
Pods/HWPopController/HWPopController/Classes/Animator/HWPopControllerAnimatedTransitioning.h
generated
Executable file
35
Pods/HWPopController/HWPopController/Classes/Animator/HWPopControllerAnimatedTransitioning.h
generated
Executable file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// HWPopControllerAnimationContext.h
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/21.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <HWPopController/HWPopController.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HWPopAnimationContext : NSObject
|
||||
|
||||
@property (nonatomic, assign, readonly) HWPopState state;
|
||||
@property (nonatomic, strong, readonly) UIView *containerView;
|
||||
@property (nonatomic, assign) NSTimeInterval duration;
|
||||
|
||||
- (instancetype)initWithState:(HWPopState)state containerView:(UIView *)containerView;
|
||||
|
||||
@end
|
||||
|
||||
@interface HWPopControllerAnimatedTransitioning : NSObject <UIViewControllerAnimatedTransitioning>
|
||||
|
||||
@property (nonatomic, assign, readonly) HWPopState state;
|
||||
@property (nonatomic, weak, readonly) HWPopController *popController;
|
||||
|
||||
- (instancetype)initWithState:(HWPopState)state popController:(HWPopController *)popController NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
166
Pods/HWPopController/HWPopController/Classes/Animator/HWPopControllerAnimatedTransitioning.m
generated
Executable file
166
Pods/HWPopController/HWPopController/Classes/Animator/HWPopControllerAnimatedTransitioning.m
generated
Executable file
@@ -0,0 +1,166 @@
|
||||
//
|
||||
// HWPopControllerAnimationContext.m
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/21.
|
||||
//
|
||||
|
||||
#import "HWPopControllerAnimatedTransitioning.h"
|
||||
#import "HWDefaultPopAnimator.h"
|
||||
|
||||
@implementation HWPopAnimationContext
|
||||
|
||||
- (instancetype)initWithState:(HWPopState)state containerView:(UIView *)containerView {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_state = state;
|
||||
_containerView = containerView;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@interface HWPopControllerAnimatedTransitioning ()
|
||||
|
||||
@property (nonatomic, strong) id<HWPopControllerAnimationProtocol> animator;
|
||||
|
||||
@end
|
||||
|
||||
@interface HWPopControllerAnimatedTransitioning ()
|
||||
|
||||
@property (nonatomic, strong, readonly) UIView *containerView;
|
||||
@property (nonatomic, strong, readonly) UIView *backgroundView;
|
||||
@property (nonatomic, strong) HWPopAnimationContext *animationContext;
|
||||
|
||||
@end
|
||||
|
||||
@implementation HWPopControllerAnimatedTransitioning
|
||||
|
||||
- (instancetype)initWithState:(HWPopState)state popController:(HWPopController *)popController {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_state = state;
|
||||
_popController = popController;
|
||||
_containerView = _popController.containerView;
|
||||
_backgroundView = _popController.backgroundView;
|
||||
_animationContext = [[HWPopAnimationContext alloc] initWithState:state containerView:_containerView];
|
||||
_animationContext.duration = _popController.animationDuration;
|
||||
|
||||
[self getAnimator];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)getAnimator {
|
||||
if (self.popController.animationProtocol) {
|
||||
self.animator = self.popController.animationProtocol;
|
||||
} else {
|
||||
HWDefaultPopAnimator *defaultPopAnimator = [HWDefaultPopAnimator new];
|
||||
defaultPopAnimator.popType = self.popController.popType;
|
||||
defaultPopAnimator.dismissType = self.popController.dismissType;
|
||||
self.animator = defaultPopAnimator;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Animation
|
||||
|
||||
- (void)popAnimateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
|
||||
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
|
||||
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
|
||||
toViewController.view.frame = fromViewController.view.frame;
|
||||
|
||||
UIViewController *topViewController = self.popController.topViewController;
|
||||
[fromViewController beginAppearanceTransition:NO animated:YES];
|
||||
|
||||
[[transitionContext containerView] addSubview:toViewController.view];
|
||||
|
||||
[topViewController beginAppearanceTransition:YES animated:YES];
|
||||
[toViewController addChildViewController:topViewController];
|
||||
[self.popController.contentView addSubview:topViewController.view];
|
||||
|
||||
[self.popController layoutContainerView];
|
||||
|
||||
CGFloat lastBackgroundViewAlpha = self.backgroundView.alpha;
|
||||
self.backgroundView.alpha = 0;
|
||||
[self setContainerUserInteractionEnabled:NO];
|
||||
self.containerView.transform = CGAffineTransformIdentity;
|
||||
|
||||
[UIView animateWithDuration:[self.animator popControllerAnimationDuration:self.animationContext] delay:0 usingSpringWithDamping:1 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
self.backgroundView.alpha = lastBackgroundViewAlpha;
|
||||
} completion:nil];
|
||||
|
||||
[self.animator popAnimate:self.animationContext completion:^(BOOL finished){
|
||||
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
|
||||
|
||||
[self setContainerUserInteractionEnabled:YES];
|
||||
|
||||
[topViewController endAppearanceTransition];
|
||||
[topViewController didMoveToParentViewController:toViewController];
|
||||
[fromViewController endAppearanceTransition];
|
||||
[toViewController setNeedsStatusBarAppearanceUpdate];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)dismissTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
|
||||
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
|
||||
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
|
||||
toViewController.view.frame = fromViewController.view.frame;
|
||||
|
||||
UIViewController *topViewController = self.popController.topViewController;
|
||||
|
||||
[toViewController beginAppearanceTransition:YES animated:YES];
|
||||
|
||||
[topViewController beginAppearanceTransition:NO animated:YES];
|
||||
[topViewController willMoveToParentViewController:nil];
|
||||
|
||||
CGFloat lastBackgroundViewAlpha = self.backgroundView.alpha;
|
||||
[self setContainerUserInteractionEnabled:NO];
|
||||
|
||||
[UIView animateWithDuration:[self.animator popControllerAnimationDuration:self.animationContext] delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
|
||||
self.backgroundView.alpha = 0;
|
||||
} completion:nil];
|
||||
|
||||
[self.animator dismissAnimate:self.animationContext completion:^(BOOL finished){
|
||||
[self setContainerUserInteractionEnabled:YES];
|
||||
self.backgroundView.alpha = lastBackgroundViewAlpha;
|
||||
|
||||
[fromViewController.view removeFromSuperview];
|
||||
[topViewController.view removeFromSuperview];
|
||||
[topViewController removeFromParentViewController];
|
||||
[toViewController endAppearanceTransition];
|
||||
|
||||
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
- (void)setContainerUserInteractionEnabled:(BOOL)enabled {
|
||||
self.containerView.userInteractionEnabled = enabled;
|
||||
self.backgroundView.userInteractionEnabled = enabled;
|
||||
}
|
||||
|
||||
#pragma mark - UIViewControllerAnimatedTransitioning
|
||||
|
||||
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext {
|
||||
|
||||
return [self.animator popControllerAnimationDuration:self.animationContext];
|
||||
}
|
||||
|
||||
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
|
||||
switch (self.state) {
|
||||
case HWPopStatePop: {
|
||||
[self popAnimateTransition:transitionContext];
|
||||
}
|
||||
break;
|
||||
case HWPopStateDismiss:{
|
||||
[self dismissTransition:transitionContext];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
25
Pods/HWPopController/HWPopController/Classes/Animator/HWPopControllerAnimationProtocol.h
generated
Executable file
25
Pods/HWPopController/HWPopController/Classes/Animator/HWPopControllerAnimationProtocol.h
generated
Executable file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// HWPopControllerAnimationProtocol.h
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/22.
|
||||
//
|
||||
|
||||
#ifndef HWPopControllerAnimationProtocol_h
|
||||
#define HWPopControllerAnimationProtocol_h
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class HWPopAnimationContext;
|
||||
|
||||
@protocol HWPopControllerAnimationProtocol <NSObject>
|
||||
|
||||
- (NSTimeInterval)popControllerAnimationDuration:(HWPopAnimationContext *)context;
|
||||
- (void)popAnimate:(HWPopAnimationContext *)context completion:(void (^)(BOOL finished))completion;
|
||||
- (void)dismissAnimate:(HWPopAnimationContext *)context completion:(void (^)(BOOL finished))completion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif /* HWPopControllerAnimationProtocol_h */
|
||||
19
Pods/HWPopController/HWPopController/Classes/Category/NSObject+HWAdd.h
generated
Executable file
19
Pods/HWPopController/HWPopController/Classes/Category/NSObject+HWAdd.h
generated
Executable file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// NSObject+HWAdd.h
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/21.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSObject (HWAdd)
|
||||
|
||||
+ (BOOL)hw_swizzleInstanceMethod:(SEL)originalSel with:(SEL)newSel;
|
||||
|
||||
+ (BOOL)hw_swizzleClassMethod:(SEL)originalSel with:(SEL)newSel;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
41
Pods/HWPopController/HWPopController/Classes/Category/NSObject+HWAdd.m
generated
Executable file
41
Pods/HWPopController/HWPopController/Classes/Category/NSObject+HWAdd.m
generated
Executable file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// NSObject+HWAdd.m
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/21.
|
||||
//
|
||||
|
||||
#import "NSObject+HWAdd.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation NSObject (HWAdd)
|
||||
|
||||
+ (BOOL)hw_swizzleInstanceMethod:(SEL)originalSel with:(SEL)newSel {
|
||||
Method originalMethod = class_getInstanceMethod(self, originalSel);
|
||||
Method newMethod = class_getInstanceMethod(self, newSel);
|
||||
if (!originalMethod || !newMethod) return NO;
|
||||
|
||||
class_addMethod(self,
|
||||
originalSel,
|
||||
class_getMethodImplementation(self, originalSel),
|
||||
method_getTypeEncoding(originalMethod));
|
||||
class_addMethod(self,
|
||||
newSel,
|
||||
class_getMethodImplementation(self, newSel),
|
||||
method_getTypeEncoding(newMethod));
|
||||
|
||||
method_exchangeImplementations(class_getInstanceMethod(self, originalSel),
|
||||
class_getInstanceMethod(self, newSel));
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL)hw_swizzleClassMethod:(SEL)originalSel with:(SEL)newSel {
|
||||
Class class = object_getClass(self);
|
||||
Method originalMethod = class_getInstanceMethod(class, originalSel);
|
||||
Method newMethod = class_getInstanceMethod(class, newSel);
|
||||
if (!originalMethod || !newMethod) return NO;
|
||||
method_exchangeImplementations(originalMethod, newMethod);
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
59
Pods/HWPopController/HWPopController/Classes/Category/UIViewController+HWPopController.h
generated
Executable file
59
Pods/HWPopController/HWPopController/Classes/Category/UIViewController+HWPopController.h
generated
Executable file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// UIViewController+HWPopController.h
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/21.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <HWPopController/HWPopController.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UIViewController (HWPopController)
|
||||
|
||||
/**
|
||||
* pop size for portrait orientation.
|
||||
*/
|
||||
@property (nonatomic, assign) IBInspectable CGSize contentSizeInPop;
|
||||
/**
|
||||
* pop size for landscape orientation
|
||||
*/
|
||||
@property (nonatomic, assign) IBInspectable CGSize contentSizeInPopWhenLandscape;
|
||||
|
||||
/**
|
||||
* The pop ViewController referred HWPopController
|
||||
*/
|
||||
@property (nullable, nonatomic, weak, readonly) HWPopController *popController;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIViewController (HWPop)
|
||||
|
||||
/**
|
||||
* The controller which will be pop call this method to popup.
|
||||
* Use default param.
|
||||
* @return HWPopController
|
||||
*/
|
||||
- (HWPopController *)popup;
|
||||
|
||||
- (HWPopController *)popupWithPopType:(HWPopType)popType
|
||||
dismissType:(HWDismissType)dismissType;
|
||||
|
||||
- (HWPopController *)popupWithPopType:(HWPopType)popType
|
||||
dismissType:(HWDismissType)dismissType
|
||||
position:(HWPopPosition)popPosition;
|
||||
|
||||
- (HWPopController *)popupWithPopType:(HWPopType)popType
|
||||
dismissType:(HWDismissType)dismissType
|
||||
position:(HWPopPosition)popPosition
|
||||
dismissOnBackgroundTouch:(BOOL)shouldDismissOnBackgroundTouch;
|
||||
|
||||
- (HWPopController *)popupWithPopType:(HWPopType)popType
|
||||
dismissType:(HWDismissType)dismissType
|
||||
position:(HWPopPosition)popPosition
|
||||
inViewController:(UIViewController *)inViewController
|
||||
dismissOnBackgroundTouch:(BOOL)shouldDismissOnBackgroundTouch;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
192
Pods/HWPopController/HWPopController/Classes/Category/UIViewController+HWPopController.m
generated
Executable file
192
Pods/HWPopController/HWPopController/Classes/Category/UIViewController+HWPopController.m
generated
Executable file
@@ -0,0 +1,192 @@
|
||||
//
|
||||
// UIViewController+HWPopController.m
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/21.
|
||||
//
|
||||
|
||||
#import "UIViewController+HWPopController.h"
|
||||
#import <objc/runtime.h>
|
||||
#import "NSObject+HWAdd.h"
|
||||
|
||||
@implementation UIViewController (HWPopController)
|
||||
|
||||
@dynamic contentSizeInPop;
|
||||
@dynamic contentSizeInPopWhenLandscape;
|
||||
@dynamic popController;
|
||||
|
||||
static inline BOOL HW_FLOAT_VALUE_IS_ZERO(CGFloat value) {
|
||||
return (value > -FLT_EPSILON) && (value < FLT_EPSILON);
|
||||
}
|
||||
|
||||
+ (void)load {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
[self hw_swizzleInstanceMethod:@selector(viewDidLoad) with:@selector(hw_viewDidLoad)];
|
||||
[self hw_swizzleInstanceMethod:@selector(presentViewController:animated:completion:) with:@selector(hw_presentViewController:animated:completion:)];
|
||||
[self hw_swizzleInstanceMethod:@selector(dismissViewControllerAnimated:completion:) with:@selector(hw_dismissViewControllerAnimated:completion:)];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)hw_viewDidLoad {
|
||||
|
||||
[self hw_viewDidLoad];
|
||||
|
||||
CGSize contentSize;
|
||||
switch ([UIApplication sharedApplication].statusBarOrientation) {
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
case UIInterfaceOrientationLandscapeRight:{
|
||||
contentSize = self.contentSizeInPopWhenLandscape;
|
||||
if (CGSizeEqualToSize(contentSize, CGSizeZero)) {
|
||||
contentSize = self.contentSizeInPop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:{
|
||||
contentSize = self.contentSizeInPop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!CGSizeEqualToSize(contentSize, CGSizeZero)) {
|
||||
self.view.frame = CGRectMake(0, 0, contentSize.width, contentSize.height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)hw_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
|
||||
if (!self.popController) {
|
||||
[self hw_presentViewController:viewControllerToPresent animated:flag completion:completion];
|
||||
return;
|
||||
}
|
||||
|
||||
[[self.popController valueForKey:@"containerViewController"] hw_presentViewController:viewControllerToPresent animated:flag completion:completion];
|
||||
}
|
||||
|
||||
- (void)hw_dismissViewControllerAnimated:(BOOL)flag completion:(void (^ __nullable)(void))completion {
|
||||
if (!self.popController) {
|
||||
[self hw_dismissViewControllerAnimated:flag completion:completion];
|
||||
return;
|
||||
}
|
||||
|
||||
[self.popController dismissWithCompletion:completion];
|
||||
}
|
||||
|
||||
#pragma mark - props
|
||||
|
||||
- (CGSize)contentSizeInPop {
|
||||
NSValue *value = objc_getAssociatedObject(self, _cmd);
|
||||
return [value CGSizeValue];
|
||||
}
|
||||
|
||||
- (void)setContentSizeInPop:(CGSize)contentSizeInPop {
|
||||
if (!CGSizeEqualToSize(contentSizeInPop, CGSizeZero) && HW_FLOAT_VALUE_IS_ZERO(contentSizeInPop.width)) {
|
||||
switch ([UIApplication sharedApplication].statusBarOrientation) {
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
case UIInterfaceOrientationLandscapeRight:{
|
||||
contentSizeInPop.width = [UIScreen mainScreen].bounds.size.height;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
contentSizeInPop.width = [UIScreen mainScreen].bounds.size.width;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
objc_setAssociatedObject(self, @selector(contentSizeInPop), [NSValue valueWithCGSize:contentSizeInPop], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (CGSize)contentSizeInPopWhenLandscape {
|
||||
NSValue *value = objc_getAssociatedObject(self, _cmd);
|
||||
return [value CGSizeValue];
|
||||
}
|
||||
|
||||
- (void)setContentSizeInPopWhenLandscape:(CGSize)contentSizeInPopWhenLandscape {
|
||||
if (!CGSizeEqualToSize(contentSizeInPopWhenLandscape, CGSizeZero) && HW_FLOAT_VALUE_IS_ZERO(contentSizeInPopWhenLandscape.width)) {
|
||||
switch ([UIApplication sharedApplication].statusBarOrientation) {
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
case UIInterfaceOrientationLandscapeRight:{
|
||||
contentSizeInPopWhenLandscape.width = [UIScreen mainScreen].bounds.size.width;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
contentSizeInPopWhenLandscape.width = [UIScreen mainScreen].bounds.size.height;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
objc_setAssociatedObject(self, @selector(contentSizeInPopWhenLandscape), [NSValue valueWithCGSize:contentSizeInPopWhenLandscape], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (HWPopController *)popController {
|
||||
HWPopController *popController = objc_getAssociatedObject(self, _cmd);
|
||||
return popController;
|
||||
}
|
||||
|
||||
- (void)setPopController:(HWPopController *)popController {
|
||||
objc_setAssociatedObject(self, @selector(popController), popController, OBJC_ASSOCIATION_ASSIGN);
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
UIViewController *HWGetTopMostViewController() {
|
||||
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
|
||||
UIViewController *topVC = keyWindow.rootViewController;
|
||||
while (topVC.presentedViewController) {
|
||||
topVC = topVC.presentedViewController;
|
||||
}
|
||||
|
||||
if ([topVC isKindOfClass:[UINavigationController class]]) {
|
||||
topVC = ((UINavigationController *) topVC).topViewController;
|
||||
}
|
||||
|
||||
if ([topVC isKindOfClass:[UITabBarController class]]) {
|
||||
topVC = ((UITabBarController *) topVC).selectedViewController;
|
||||
}
|
||||
|
||||
return topVC;
|
||||
}
|
||||
|
||||
@implementation UIViewController (HWPop)
|
||||
|
||||
- (HWPopController *)popup {
|
||||
return [self popupWithPopType:HWPopTypeGrowIn dismissType:HWDismissTypeFadeOut position:HWPopPositionCenter inViewController:HWGetTopMostViewController() dismissOnBackgroundTouch:YES];
|
||||
}
|
||||
|
||||
- (HWPopController *)popupWithPopType:(HWPopType)popType dismissType:(HWDismissType)dismissType{
|
||||
return [self popupWithPopType:popType dismissType:dismissType position:HWPopPositionCenter];
|
||||
}
|
||||
|
||||
- (HWPopController *)popupWithPopType:(HWPopType)popType
|
||||
dismissType:(HWDismissType)dismissType
|
||||
position:(HWPopPosition)popPosition {
|
||||
return [self popupWithPopType:popType dismissType:dismissType position:popPosition inViewController:HWGetTopMostViewController() dismissOnBackgroundTouch:YES];
|
||||
}
|
||||
|
||||
- (HWPopController *)popupWithPopType:(HWPopType)popType
|
||||
dismissType:(HWDismissType)dismissType
|
||||
position:(HWPopPosition)popPosition
|
||||
dismissOnBackgroundTouch:(BOOL)shouldDismissOnBackgroundTouch {
|
||||
return [self popupWithPopType:popType dismissType:dismissType position:popPosition inViewController:HWGetTopMostViewController() dismissOnBackgroundTouch:shouldDismissOnBackgroundTouch];
|
||||
}
|
||||
|
||||
- (HWPopController *)popupWithPopType:(HWPopType)popType
|
||||
dismissType:(HWDismissType)dismissType
|
||||
position:(HWPopPosition)popPosition
|
||||
inViewController:(UIViewController *)inViewController
|
||||
dismissOnBackgroundTouch:(BOOL)shouldDismissOnBackgroundTouch {
|
||||
HWPopController *popController = [[HWPopController alloc] initWithViewController:self];
|
||||
popController.popType = popType;
|
||||
popController.dismissType = dismissType;
|
||||
popController.popPosition = popPosition;
|
||||
popController.shouldDismissOnBackgroundTouch = shouldDismissOnBackgroundTouch;
|
||||
[popController presentInViewController:inViewController];
|
||||
return popController;
|
||||
}
|
||||
|
||||
@end
|
||||
164
Pods/HWPopController/HWPopController/Classes/Controller/HWPopController.h
generated
Executable file
164
Pods/HWPopController/HWPopController/Classes/Controller/HWPopController.h
generated
Executable file
@@ -0,0 +1,164 @@
|
||||
//
|
||||
// HWPopController.h
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/21.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <HWPopController/HWPopControllerAnimationProtocol.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSInteger, HWPopPosition) {
|
||||
HWPopPositionCenter,
|
||||
HWPopPositionTop,
|
||||
HWPopPositionBottom,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, HWPopState) {
|
||||
HWPopStatePop, // present
|
||||
HWPopStateDismiss, // dismiss
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, HWPopType) {
|
||||
HWPopTypeNone,
|
||||
HWPopTypeFadeIn,
|
||||
HWPopTypeGrowIn,
|
||||
HWPopTypeShrinkIn,
|
||||
HWPopTypeSlideInFromTop,
|
||||
HWPopTypeSlideInFromBottom,
|
||||
HWPopTypeSlideInFromLeft,
|
||||
HWPopTypeSlideInFromRight,
|
||||
HWPopTypeBounceIn,
|
||||
HWPopTypeBounceInFromTop,
|
||||
HWPopTypeBounceInFromBottom,
|
||||
HWPopTypeBounceInFromLeft,
|
||||
HWPopTypeBounceInFromRight,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, HWDismissType) {
|
||||
HWDismissTypeNone,
|
||||
HWDismissTypeFadeOut,
|
||||
HWDismissTypeGrowOut,
|
||||
HWDismissTypeShrinkOut,
|
||||
HWDismissTypeSlideOutToTop,
|
||||
HWDismissTypeSlideOutToBottom,
|
||||
HWDismissTypeSlideOutToLeft,
|
||||
HWDismissTypeSlideOutToRight,
|
||||
HWDismissTypeBounceOut,
|
||||
HWDismissTypeBounceOutToTop,
|
||||
HWDismissTypeBounceOutToBottom,
|
||||
HWDismissTypeBounceOutToLeft,
|
||||
HWDismissTypeBounceOutToRight,
|
||||
};
|
||||
|
||||
@interface HWPopController : NSObject
|
||||
|
||||
#pragma mark - config properties
|
||||
|
||||
/**
|
||||
//////////////////////////////////////////////////////
|
||||
Below props should be set when you pop the controller.
|
||||
//////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
/**
|
||||
* pop animation style
|
||||
* default is HWPopTypeGrowIn
|
||||
*/
|
||||
@property (nonatomic, assign) HWPopType popType;
|
||||
/**
|
||||
* dismiss animation style
|
||||
* default is HWDismissTypeFadeOut
|
||||
*/
|
||||
@property (nonatomic, assign) HWDismissType dismissType;
|
||||
/**
|
||||
* animation duration
|
||||
* default is 0.2 s
|
||||
*/
|
||||
@property (nonatomic, assign) NSTimeInterval animationDuration;
|
||||
/**
|
||||
* The pop view final position.
|
||||
* Default is HWPopPositionCenter
|
||||
*/
|
||||
@property (nonatomic, assign) HWPopPosition popPosition;
|
||||
/**
|
||||
* The offset of the pop view.
|
||||
*/
|
||||
@property (nonatomic, assign) CGPoint positionOffset;
|
||||
/**
|
||||
* You can custom your own animation for pop and dismiss.
|
||||
* once you set this property, and NOT nil,
|
||||
* the `popType` and `dismissType` will be ignore.
|
||||
*/
|
||||
@property (nonatomic, weak) id<HWPopControllerAnimationProtocol> animationProtocol;
|
||||
@property (nonatomic, assign) UIEdgeInsets safeAreaInsets;
|
||||
|
||||
/**
|
||||
//////////////////////////////////////////////////////
|
||||
Below props can be set when you need.
|
||||
//////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
/**
|
||||
* The background when popup. You can set it as `UIImageView`, `UIVisualEffectView` such as.
|
||||
*/
|
||||
@property (nullable, nonatomic, strong) UIView *backgroundView;
|
||||
/**
|
||||
* pop background alpha.
|
||||
* default is 0.5
|
||||
*/
|
||||
@property (nonatomic, assign) CGFloat backgroundAlpha;
|
||||
/**
|
||||
* determine touch background to dismiss
|
||||
* Default is YES.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL shouldDismissOnBackgroundTouch;
|
||||
|
||||
/// Default is YES
|
||||
@property (nonatomic, assign) BOOL shouldAutoHandleKeyboardEvent;
|
||||
|
||||
#pragma mark - readonly properties
|
||||
|
||||
/**
|
||||
* Hold the pop view container.
|
||||
* Default the backgroundColor is White.
|
||||
* Default the corner radius is 8.0f.
|
||||
* If you want to custom corner, change containerView layer.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) UIView *containerView;
|
||||
/**
|
||||
* Which view the popped ViewController view added.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) UIView *contentView;
|
||||
|
||||
/**
|
||||
* topViewController is the viewController which is presented.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) UIViewController *topViewController;
|
||||
@property (nonatomic, assign, readonly) BOOL presented;
|
||||
|
||||
/**
|
||||
* init PopController
|
||||
* @param presentedViewController the controller which will be presented
|
||||
*/
|
||||
- (instancetype)initWithViewController:(UIViewController *)presentedViewController;
|
||||
|
||||
/**
|
||||
* pop controller
|
||||
* @param presentingViewController which controller to present.
|
||||
*/
|
||||
- (void)presentInViewController:(UIViewController *)presentingViewController;
|
||||
|
||||
- (void)presentInViewController:(UIViewController *)presentingViewController completion:(nullable void (^)(void))completion;
|
||||
|
||||
- (void)dismiss;
|
||||
|
||||
- (void)dismissWithCompletion:(nullable void (^)(void))completion;
|
||||
|
||||
- (void)layoutContainerView;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
432
Pods/HWPopController/HWPopController/Classes/Controller/HWPopController.m
generated
Executable file
432
Pods/HWPopController/HWPopController/Classes/Controller/HWPopController.m
generated
Executable file
@@ -0,0 +1,432 @@
|
||||
//
|
||||
// HWPopController.m
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/21.
|
||||
//
|
||||
|
||||
#import "HWPopController.h"
|
||||
#import "UIViewController+HWPopController.h"
|
||||
#import "HWPopTransitioningDelegate.h"
|
||||
|
||||
static NSMutableSet *_retainedPopControllers;
|
||||
|
||||
@interface UIViewController (Internal)
|
||||
|
||||
@property (nonatomic, weak) HWPopController *popController;
|
||||
|
||||
@end
|
||||
|
||||
@interface HWPopContainerViewController : UIViewController
|
||||
|
||||
@end
|
||||
|
||||
@implementation HWPopContainerViewController
|
||||
|
||||
@end
|
||||
|
||||
@interface HWPopController ()
|
||||
|
||||
@property (nonatomic, strong) HWPopContainerViewController *containerViewController;
|
||||
@property (nonatomic, strong) UIViewController *topViewController;
|
||||
|
||||
@property (nonatomic, strong) UIView *containerView;
|
||||
@property (nonatomic, strong) UIView *contentView;
|
||||
|
||||
@property (nonatomic, assign) BOOL didOverrideSafeAreaInsets;
|
||||
@property (nonatomic, assign) BOOL isObserving;
|
||||
|
||||
@property (nonatomic, copy) NSDictionary *keyboardInfo;
|
||||
|
||||
@property (nonatomic, strong) HWPopTransitioningDelegate *transitioningDelegate;
|
||||
|
||||
@end
|
||||
|
||||
@implementation HWPopController
|
||||
|
||||
#pragma mark - init
|
||||
|
||||
+ (void)load {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_retainedPopControllers = [NSMutableSet set];
|
||||
});
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self setup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - public method
|
||||
|
||||
- (instancetype)initWithViewController:(UIViewController *)viewController {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
self.topViewController = viewController;
|
||||
// set popController to the popped viewController
|
||||
viewController.popController = self;
|
||||
[self setupObserverForViewController:viewController];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)presentInViewController:(UIViewController *)presentingViewController {
|
||||
[self presentInViewController:presentingViewController completion:nil];
|
||||
}
|
||||
|
||||
- (void)presentInViewController:(UIViewController *)presentingViewController completion:(nullable void (^)(void))completion {
|
||||
if (self.presented)
|
||||
return;
|
||||
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self setupObserver];
|
||||
[_retainedPopControllers addObject:self];
|
||||
|
||||
UIViewController *VC = presentingViewController.tabBarController ?: presentingViewController;
|
||||
|
||||
if (@available(iOS 11.0, *)) {
|
||||
if (!self.didOverrideSafeAreaInsets) {
|
||||
self.safeAreaInsets = presentingViewController.view.safeAreaInsets;
|
||||
}
|
||||
}
|
||||
|
||||
[VC presentViewController:self.containerViewController animated:YES completion:completion];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)dismiss {
|
||||
[self dismissWithCompletion:nil];
|
||||
}
|
||||
|
||||
- (void)dismissWithCompletion:(nullable void (^)(void))completion {
|
||||
if (!self.presented)
|
||||
return;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self destroyObserver];
|
||||
[self.containerViewController dismissViewControllerAnimated:YES completion:^{
|
||||
[_retainedPopControllers removeObject:self];
|
||||
completion ? completion() : nil;
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - observe
|
||||
|
||||
- (void)setupObserverForViewController:(UIViewController *)viewController {
|
||||
[viewController addObserver:self forKeyPath:NSStringFromSelector(@selector(contentSizeInPop)) options:NSKeyValueObservingOptionNew context:nil];
|
||||
[viewController addObserver:self forKeyPath:NSStringFromSelector(@selector(contentSizeInPopWhenLandscape)) options:NSKeyValueObservingOptionNew context:nil];
|
||||
}
|
||||
|
||||
- (void)setupObserver {
|
||||
if (self.isObserving)
|
||||
return;
|
||||
|
||||
// Observe orientation change
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationDidChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
|
||||
|
||||
if (self.shouldAutoHandleKeyboardEvent) {
|
||||
// Observe keyboard
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillChangeFrameNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
|
||||
}
|
||||
|
||||
self.isObserving = YES;
|
||||
}
|
||||
|
||||
- (void)destroyObserver {
|
||||
if (!self.isObserving)
|
||||
return;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
self.isObserving = NO;
|
||||
}
|
||||
|
||||
- (void)destroyObserverOfViewController:(UIViewController *)viewController {
|
||||
[viewController removeObserver:self forKeyPath:NSStringFromSelector(@selector(contentSizeInPop))];
|
||||
[viewController removeObserver:self forKeyPath:NSStringFromSelector(@selector(contentSizeInPopWhenLandscape))];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context {
|
||||
if (object == self.topViewController) {
|
||||
if (self.topViewController.isViewLoaded && self.topViewController.view.superview) {
|
||||
[UIView animateWithDuration:0.35 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
|
||||
[self layoutContainerView];
|
||||
} completion:^(BOOL finished) {
|
||||
[self adjustContainerViewOrigin];
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UIApplicationDidChangeStatusBarOrientationNotification
|
||||
|
||||
- (void)orientationDidChange {
|
||||
[self.containerView endEditing:YES];
|
||||
[UIView animateWithDuration:0.25 animations:^{
|
||||
[self layoutContainerView];
|
||||
} completion:^(BOOL finished) {
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - keyboard handle
|
||||
|
||||
- (void)adjustContainerViewOrigin {
|
||||
|
||||
if (!self.keyboardInfo)
|
||||
return;
|
||||
|
||||
UIView <UIKeyInput> *currentTextInput = [self getCurrentTextInputInView:self.containerView];
|
||||
if (!currentTextInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGAffineTransform lastTransform = self.containerView.transform;
|
||||
self.containerView.transform = CGAffineTransformIdentity;
|
||||
|
||||
CGFloat textFieldBottomY = [currentTextInput convertPoint:CGPointZero toView:self.containerViewController.view].y + currentTextInput.bounds.size.height;
|
||||
CGFloat keyboardHeight = [self.keyboardInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
|
||||
// For iOS 7
|
||||
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
|
||||
if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1 &&
|
||||
(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight)) {
|
||||
keyboardHeight = [self.keyboardInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.width;
|
||||
}
|
||||
|
||||
CGFloat offsetY = 0;
|
||||
if (self.popPosition == HWPopPositionBottom) {
|
||||
offsetY = keyboardHeight - _safeAreaInsets.bottom;
|
||||
} else {
|
||||
CGFloat statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;
|
||||
if (self.containerView.bounds.size.height <= self.containerViewController.view.bounds.size.height - keyboardHeight - statusBarHeight) {
|
||||
offsetY = self.containerView.frame.origin.y - (statusBarHeight + (self.containerViewController.view.bounds.size.height - keyboardHeight - statusBarHeight - self.containerView.bounds.size.height) / 2);
|
||||
} else {
|
||||
CGFloat spacing = 5;
|
||||
offsetY = self.containerView.frame.origin.y + self.containerView.bounds.size.height - (self.containerViewController.view.bounds.size.height - keyboardHeight - spacing);
|
||||
if (offsetY <= 0) { // self.containerView can be totally shown, so no need to translate the origin
|
||||
return;
|
||||
}
|
||||
if (self.containerView.frame.origin.y - offsetY < statusBarHeight) { // self.containerView will be covered by status bar if the origin is translated by "offsetY"
|
||||
offsetY = self.containerView.frame.origin.y - statusBarHeight;
|
||||
// currentTextField can not be totally shown if self.containerView is going to repositioned with "offsetY"
|
||||
if (textFieldBottomY - offsetY > self.containerViewController.view.bounds.size.height - keyboardHeight - spacing) {
|
||||
offsetY = textFieldBottomY - (self.containerViewController.view.bounds.size.height - keyboardHeight - spacing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSTimeInterval duration = [self.keyboardInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
|
||||
UIViewAnimationCurve curve = [self.keyboardInfo[UIKeyboardAnimationCurveUserInfoKey] intValue];
|
||||
|
||||
self.containerView.transform = lastTransform; // Restore transform
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationBeginsFromCurrentState:YES];
|
||||
[UIView setAnimationCurve:curve];
|
||||
[UIView setAnimationDuration:duration];
|
||||
|
||||
self.containerView.transform = CGAffineTransformMakeTranslation(0, -offsetY);
|
||||
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification {
|
||||
if (!self.shouldAutoHandleKeyboardEvent) return;
|
||||
|
||||
UIView <UIKeyInput> *currentTextInput = [self getCurrentTextInputInView:self.containerView];
|
||||
if (!currentTextInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.keyboardInfo = notification.userInfo;
|
||||
[self adjustContainerViewOrigin];
|
||||
}
|
||||
|
||||
- (void)keyboardWillHide:(NSNotification *)notification {
|
||||
if (!self.shouldAutoHandleKeyboardEvent) return;
|
||||
self.keyboardInfo = nil;
|
||||
|
||||
NSTimeInterval duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
|
||||
UIViewAnimationCurve curve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationBeginsFromCurrentState:YES];
|
||||
[UIView setAnimationCurve:curve];
|
||||
[UIView setAnimationDuration:duration];
|
||||
|
||||
self.containerView.transform = CGAffineTransformIdentity;
|
||||
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
- (UIView <UIKeyInput> *)getCurrentTextInputInView:(UIView *)view {
|
||||
if ([view conformsToProtocol:@protocol(UIKeyInput)] && view.isFirstResponder) {
|
||||
// Quick fix for web view issue
|
||||
if ([view isKindOfClass:NSClassFromString(@"UIWebBrowserView")] || [view isKindOfClass:NSClassFromString(@"WKContentView")]) {
|
||||
return nil;
|
||||
}
|
||||
return (UIView <UIKeyInput> *) view;
|
||||
}
|
||||
|
||||
for (UIView *subview in view.subviews) {
|
||||
UIView <UIKeyInput> *inputInView = [self getCurrentTextInputInView:subview];
|
||||
if (inputInView) {
|
||||
return inputInView;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - touch event
|
||||
|
||||
- (void)didTapBackgroundView {
|
||||
if (self.shouldDismissOnBackgroundTouch) {
|
||||
[self dismiss];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UI Layout
|
||||
|
||||
- (void)layoutContainerView {
|
||||
CGAffineTransform lastTransform = self.containerView.transform;
|
||||
self.containerView.transform = CGAffineTransformIdentity;
|
||||
|
||||
self.backgroundView.frame = self.containerViewController.view.bounds;
|
||||
|
||||
CGSize contentSizeOfTopView = [self contentSizeOfTopView];
|
||||
CGFloat containerViewWidth = contentSizeOfTopView.width;
|
||||
CGFloat containerViewHeight = contentSizeOfTopView.height;
|
||||
CGFloat containerViewY;
|
||||
|
||||
switch (self.popPosition) {
|
||||
case HWPopPositionBottom:{
|
||||
containerViewHeight += _safeAreaInsets.bottom;
|
||||
containerViewY = self.containerViewController.view.bounds.size.height - containerViewHeight;
|
||||
}
|
||||
break;
|
||||
case HWPopPositionTop:{
|
||||
containerViewY = 0;
|
||||
}
|
||||
break;
|
||||
default:{
|
||||
containerViewY = (self.containerViewController.view.bounds.size.height - containerViewHeight) / 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
containerViewY += self.positionOffset.y;
|
||||
CGFloat containerViewX = (self.containerViewController.view.bounds.size.width - containerViewWidth) / 2 + self.positionOffset.x;
|
||||
self.containerView.frame = CGRectMake(containerViewX, containerViewY, containerViewWidth, containerViewHeight);
|
||||
self.contentView.frame = CGRectMake(0, 0, contentSizeOfTopView.width, contentSizeOfTopView.height);
|
||||
|
||||
UIViewController *topViewController = self.topViewController;
|
||||
topViewController.view.frame = self.contentView.bounds;
|
||||
|
||||
self.containerView.transform = lastTransform;
|
||||
}
|
||||
|
||||
- (CGSize)contentSizeOfTopView {
|
||||
UIViewController *topViewController = self.topViewController;
|
||||
CGSize contentSize;
|
||||
switch ([UIApplication sharedApplication].statusBarOrientation) {
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
case UIInterfaceOrientationLandscapeRight: {
|
||||
contentSize = topViewController.contentSizeInPopWhenLandscape;
|
||||
if (CGSizeEqualToSize(contentSize, CGSizeZero)) {
|
||||
contentSize = topViewController.contentSizeInPop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
contentSize = topViewController.contentSizeInPop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
NSAssert(!CGSizeEqualToSize(contentSize, CGSizeZero), @"contentSizeInPopup should not be size zero.");
|
||||
return contentSize;
|
||||
}
|
||||
|
||||
#pragma mark - UI prepare
|
||||
|
||||
- (void)setup {
|
||||
self.shouldDismissOnBackgroundTouch = YES;
|
||||
self.shouldAutoHandleKeyboardEvent = YES;
|
||||
self.animationDuration = 0.2;
|
||||
self.popType = HWPopTypeGrowIn;
|
||||
self.dismissType = HWDismissTypeFadeOut;
|
||||
|
||||
[self.containerViewController.view addSubview:self.containerView];
|
||||
[self.containerView addSubview:self.contentView];
|
||||
|
||||
UIView *bgView = [UIView new];
|
||||
self.backgroundView = bgView;
|
||||
self.backgroundAlpha = 0.5;
|
||||
}
|
||||
|
||||
#pragma mark - Setter
|
||||
|
||||
- (void)setSafeAreaInsets:(UIEdgeInsets)safeAreaInsets {
|
||||
_safeAreaInsets = safeAreaInsets;
|
||||
self.didOverrideSafeAreaInsets = YES;
|
||||
}
|
||||
|
||||
- (void)setBackgroundView:(UIView *)backgroundView {
|
||||
[_backgroundView removeFromSuperview];
|
||||
_backgroundView = backgroundView;
|
||||
[_backgroundView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapBackgroundView)]];
|
||||
[self.containerViewController.view insertSubview:_backgroundView atIndex:0];
|
||||
}
|
||||
|
||||
- (void)setBackgroundAlpha:(CGFloat)backgroundAlpha {
|
||||
_backgroundAlpha = backgroundAlpha;
|
||||
self.backgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:backgroundAlpha];
|
||||
}
|
||||
|
||||
#pragma mark - Getter
|
||||
|
||||
- (UIView *)containerView {
|
||||
if (!_containerView) {
|
||||
_containerView = [UIView new];
|
||||
_containerView.backgroundColor = [UIColor whiteColor];
|
||||
_containerView.clipsToBounds = YES;
|
||||
_containerView.layer.cornerRadius = 8;
|
||||
}
|
||||
return _containerView;
|
||||
}
|
||||
|
||||
- (HWPopContainerViewController *)containerViewController {
|
||||
if (!_containerViewController) {
|
||||
_containerViewController = [HWPopContainerViewController new];
|
||||
_containerViewController.modalPresentationStyle = UIModalPresentationCustom;
|
||||
self.transitioningDelegate = [[HWPopTransitioningDelegate alloc] initWithPopController:self];
|
||||
_containerViewController.transitioningDelegate = self.transitioningDelegate;
|
||||
}
|
||||
return _containerViewController;
|
||||
}
|
||||
|
||||
- (UIView *)contentView {
|
||||
if (!_contentView) {
|
||||
_contentView = [UIView new];
|
||||
}
|
||||
return _contentView;
|
||||
}
|
||||
|
||||
- (BOOL)presented {
|
||||
return self.containerViewController.presentingViewController != nil;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self destroyObserver];
|
||||
[self destroyObserverOfViewController:self.topViewController];
|
||||
}
|
||||
|
||||
@end
|
||||
20
Pods/HWPopController/HWPopController/Classes/Controller/HWPopNavigationController.h
generated
Executable file
20
Pods/HWPopController/HWPopController/Classes/Controller/HWPopNavigationController.h
generated
Executable file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// HWPopNavigationController.h
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/6/10.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* If you want to pop UINavigationController & dynamic change the pop contentSize:
|
||||
* You should subclass HWPopNavigationController, then use it like a normally UIViewController
|
||||
*/
|
||||
@interface HWPopNavigationController : UINavigationController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
83
Pods/HWPopController/HWPopController/Classes/Controller/HWPopNavigationController.m
generated
Executable file
83
Pods/HWPopController/HWPopController/Classes/Controller/HWPopNavigationController.m
generated
Executable file
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// HWPopNavigationController.m
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/6/10.
|
||||
//
|
||||
|
||||
#import "HWPopNavigationController.h"
|
||||
#import "HWNavAnimatedTransitioning.h"
|
||||
#import "UIViewController+HWPopController.h"
|
||||
|
||||
@interface HWPopNavigationController () <UINavigationControllerDelegate>
|
||||
|
||||
@property (nonatomic, strong) HWNavAnimatedTransitioning *animatedTransitioning;
|
||||
|
||||
@property (nonatomic, assign) CGSize originContentSizeInPop;
|
||||
@property (nonatomic, assign) CGSize originContentSizeInPopWhenLandscape;
|
||||
|
||||
@end
|
||||
|
||||
@implementation HWPopNavigationController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
self.delegate = self;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
self.originContentSizeInPop = self.contentSizeInPop;
|
||||
self.originContentSizeInPopWhenLandscape = self.contentSizeInPopWhenLandscape;
|
||||
}
|
||||
|
||||
#pragma mark - overwrite
|
||||
|
||||
- (void)adjustContentSizeBy:(UIViewController *)controller {
|
||||
|
||||
switch ([UIApplication sharedApplication].statusBarOrientation) {
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
case UIInterfaceOrientationLandscapeRight: {
|
||||
CGSize contentSize = controller.contentSizeInPopWhenLandscape;
|
||||
if (!CGSizeEqualToSize(contentSize, CGSizeZero)) {
|
||||
self.contentSizeInPopWhenLandscape = contentSize;
|
||||
} else {
|
||||
self.contentSizeInPopWhenLandscape = self.originContentSizeInPopWhenLandscape;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
CGSize contentSize = controller.contentSizeInPop;
|
||||
if (!CGSizeEqualToSize(contentSize, CGSizeZero)) {
|
||||
self.contentSizeInPop = contentSize;
|
||||
} else {
|
||||
self.contentSizeInPop = self.originContentSizeInPop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - UINavigationControllerDelegate
|
||||
|
||||
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {
|
||||
// call this to perform viewDidLoad
|
||||
[toVC view];
|
||||
[self adjustContentSizeBy:toVC];
|
||||
self.animatedTransitioning.state = operation == UINavigationControllerOperationPush ? HWPopStatePop : HWPopStateDismiss;
|
||||
return self.animatedTransitioning;
|
||||
}
|
||||
|
||||
#pragma mark - Getter
|
||||
|
||||
|
||||
- (HWNavAnimatedTransitioning *)animatedTransitioning {
|
||||
if (!_animatedTransitioning) {
|
||||
_animatedTransitioning = [[HWNavAnimatedTransitioning alloc] initWithState:HWPopStatePop];
|
||||
}
|
||||
return _animatedTransitioning;
|
||||
}
|
||||
|
||||
@end
|
||||
17
Pods/HWPopController/HWPopController/Classes/HWPop.h
generated
Executable file
17
Pods/HWPopController/HWPopController/Classes/HWPop.h
generated
Executable file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// HWPop.h
|
||||
// Pods
|
||||
//
|
||||
// Created by heath wang on 2019/5/22.
|
||||
//
|
||||
|
||||
#ifndef HWPop_h
|
||||
#define HWPop_h
|
||||
|
||||
#import <HWPopController/HWPopController.h>
|
||||
#import <HWPopController/HWPopNavigationController.h>
|
||||
#import <HWPopController/UIViewController+HWPopController.h>
|
||||
#import <HWPopController/HWPopControllerAnimationProtocol.h>
|
||||
#import <HWPopController/HWPopControllerAnimatedTransitioning.h>
|
||||
|
||||
#endif /* HWPop_h */
|
||||
25
Pods/HWPopController/HWPopController/Classes/TransitioningDelegate/HWPopTransitioningDelegate.h
generated
Executable file
25
Pods/HWPopController/HWPopController/Classes/TransitioningDelegate/HWPopTransitioningDelegate.h
generated
Executable file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// HWPopTransitioningDelegate.h
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/21.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <HWPopController/HWPopController.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HWPopTransitioningDelegate : NSObject <UIViewControllerTransitioningDelegate>
|
||||
|
||||
@property (nonatomic, weak, readonly) HWPopController *popController;
|
||||
|
||||
- (instancetype)initWithPopController:(HWPopController *)popController NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
32
Pods/HWPopController/HWPopController/Classes/TransitioningDelegate/HWPopTransitioningDelegate.m
generated
Executable file
32
Pods/HWPopController/HWPopController/Classes/TransitioningDelegate/HWPopTransitioningDelegate.m
generated
Executable file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// HWPopTransitioningDelegate.m
|
||||
// HWPopController
|
||||
//
|
||||
// Created by heath wang on 2019/5/21.
|
||||
//
|
||||
|
||||
#import "HWPopTransitioningDelegate.h"
|
||||
#import "HWPopControllerAnimatedTransitioning.h"
|
||||
|
||||
@implementation HWPopTransitioningDelegate
|
||||
|
||||
- (instancetype)initWithPopController:(HWPopController *)popController {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_popController = popController;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - UIViewControllerTransitioningDelegate
|
||||
|
||||
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
|
||||
return [[HWPopControllerAnimatedTransitioning alloc] initWithState:HWPopStatePop popController:self.popController];
|
||||
}
|
||||
|
||||
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
|
||||
return [[HWPopControllerAnimatedTransitioning alloc] initWithState:HWPopStateDismiss popController:self.popController];
|
||||
}
|
||||
|
||||
@end
|
||||
19
Pods/HWPopController/LICENSE
generated
Executable file
19
Pods/HWPopController/LICENSE
generated
Executable file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2019 Heath Wang <yishu.jay@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
146
Pods/HWPopController/README.md
generated
Executable file
146
Pods/HWPopController/README.md
generated
Executable file
@@ -0,0 +1,146 @@
|
||||
# HWPopController
|
||||
|
||||
<p style="align: left">
|
||||
<a href="https://cocoapods.org/pods/HWPopController">
|
||||
<img src="https://img.shields.io/cocoapods/v/HWPopController.svg?style=flat">
|
||||
</a>
|
||||
<a href="https://cocoapods.org/pods/HWPopController">
|
||||
<img src="https://img.shields.io/cocoapods/p/HWPopController.svg?style=flat">
|
||||
</a>
|
||||
<a href="https://cocoapods.org/pods/HWPopController">
|
||||
<img src="https://img.shields.io/badge/support-ios%208%2B-orange.svg">
|
||||
</a>
|
||||
<a href="https://cocoapods.org/pods/HWPopController">
|
||||
<img src="https://img.shields.io/badge/language-objective--c-blue.svg">
|
||||
</a>
|
||||
<a href="https://cocoapods.org/pods/HWPopController">
|
||||
<img src="https://img.shields.io/cocoapods/l/HWPopController.svg?style=flat">
|
||||
</a>
|
||||
<a href="https://cocoapods.org/pods/HWPopController">
|
||||
<img src="https://img.shields.io/badge/cocoapods-supported-4BC51D.svg?style=plastic">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
`HWPopController` can popup `UIViewController` with `multiple animations`, custom pop size in portrait / landscape screen. Popup position can be `top/center/bottom`. And you can define your own popup animations.
|
||||
|
||||
**My another project for pop view from bottom:**[**HWPanModal**](https://github.com/HeathWang/HWPanModal)
|
||||
|
||||
## Screen Shot
|
||||
|
||||
<div style="text-align: center"><table><tr>
|
||||
<td style="text-align: center">
|
||||
<img src="https://github.com/HeathWang/HWPopController/blob/master/screenshoot1.gif" width="250" />
|
||||
</td>
|
||||
<td style="text-align: center">
|
||||
<img src="https://github.com/HeathWang/HWPopController/blob/master/screenshoot2.gif" width="250"/>
|
||||
</td>
|
||||
<td style="text-align: center">
|
||||
<img src="https://github.com/HeathWang/HWPopController/blob/master/screenshoot3.gif" width="250"/>
|
||||
</td>
|
||||
</tr></table></div>
|
||||
|
||||
## Features
|
||||
* Support popup UIViewController.
|
||||
* Support popup UINavigationController, dynamic change pop size when you push/pop.
|
||||
* Support 12 kinds of pop & dismiss animations.
|
||||
* Support define your own custom animation for pop & dismiss.
|
||||
* Support popup at top/center/bottom, and use `positionOffset` to adjust x,y coordinates.
|
||||
|
||||
## Compatibility
|
||||
**iOS 8.0+**, support Objective-C & Swift.
|
||||
|
||||
## Installation
|
||||
|
||||
HWPopController is available through [CocoaPods](https://cocoapods.org). To install
|
||||
it, simply add the following line to your Podfile:
|
||||
|
||||
```ruby
|
||||
pod 'HWPopController', '~> 1.0.5'
|
||||
```
|
||||
|
||||
## How to use
|
||||
|
||||
1. Create you popup UIViewController.
|
||||
1. import HWPopController framework
|
||||
2. config `contentSizeInPop` and `contentSizeInPopWhenLandscape`(if you want to support landscape)
|
||||
|
||||
|
||||
```Objective-C
|
||||
#import "HWPop1ViewController.h"
|
||||
#import <HWPopController/HWPop.h>
|
||||
@interface HWPop1ViewController ()
|
||||
@end
|
||||
|
||||
@implementation HWPop1ViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
self.contentSizeInPop = CGSizeMake(250, 300);
|
||||
self.contentSizeInPopWhenLandscape = CGSizeMake(300, 200);
|
||||
// build you pop view.
|
||||
}
|
||||
```
|
||||
1. Popup your viewController
|
||||
|
||||
If you want high custom your popup, init HWPopController. Then config the properties what you want.
|
||||
Please see `HWPopController.h`
|
||||
|
||||
```Objective-C
|
||||
{
|
||||
HWPop1ViewController *pop1ViewController = [HWPop1ViewController new];
|
||||
HWPopController *popController = [[HWPopController alloc] initWithRootViewController:pop1ViewController];
|
||||
// popView position
|
||||
popController.popPosition = HWPopPositionTop;
|
||||
[popController presentInViewController:self];
|
||||
}
|
||||
```
|
||||
|
||||
Quick popup, use the UIViewController category.
|
||||
|
||||
```Objective-C
|
||||
HWPop1ViewController *pop1ViewController = [HWPop1ViewController new];
|
||||
[pop1ViewController popupWithPopType:HWPopTypeGrowIn dismissType:HWDismissTypeGrowOut dismissOnBackgroundTouch:YES];
|
||||
```
|
||||
|
||||
1. Dismiss pop
|
||||
Use native api.
|
||||
|
||||
```Objective-C
|
||||
[self dismissViewControllerAnimated:YES completion:^{
|
||||
|
||||
}];
|
||||
```
|
||||
|
||||
Get popController, then call popController dismiss api.
|
||||
|
||||
```Objective-C
|
||||
[self.popController dismiss];
|
||||
```
|
||||
|
||||
### Pop UINavigationController
|
||||
|
||||
If you want pop UINavigationController, and every stacked UIViewController contentSize is not same. You can use `HWPopNavigationController`.
|
||||
|
||||
`HWPopNavigationController` subclass `UINavigationController`, you can inherit from `HWPopNavigationController`, config contentSizeInPop as default contentSize.
|
||||
|
||||
When you push A Controller, then Push B Controller. A, B Controller should config contentSizeInPop if you need. If you have not config it, we will use NavigationController contentSizeInPop.
|
||||
|
||||
Relationship:
|
||||
* UINavigationController
|
||||
* HWPopNavigationController
|
||||
* Your custom UINavigationController inherit from HWPopNavigationController
|
||||
|
||||
**More details, pls see the Example.**
|
||||
|
||||
## Example
|
||||
|
||||
To run the example project, clone the repo, and run `pod install` from the Example directory first.
|
||||
|
||||
## Author
|
||||
|
||||
HeathWang, yishu.jay@gmail.com
|
||||
|
||||
## License
|
||||
|
||||
**HWPopController** is available under the MIT license. See the LICENSE file for more info.
|
||||
Reference in New Issue
Block a user