diff --git a/._README.md b/._README.md new file mode 100644 index 0000000..c893829 Binary files /dev/null and b/._README.md differ diff --git a/README.md b/README.md index 5739803..b841a8c 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,3 @@ ## UIViewController+KNSemiModal Category -UIViewController+KNSemiModal is an effort to make a replica of **semi-modal view with pushed-back stacked animation** found in the beautiful [Park Guides by National Geographic](http://itunes.apple.com/us/app/national-parks-by-national/id518426085?mt=8) app. You can see this original semi-modal view below. - -This library (ARC) is designed as a Category to UIViewController so you don't have to subclass and you can simply drop in any project and it will just work! - -*Original screenshot* - - . - -*Replica (view demo video to see the beautiful animation)* - - . - -*On iPad - - - -### Demo - -Download a demo clip [here](https://github.com/kentnguyen/KNSemiModalViewController/blob/master/Docs/KNSemiModalDemo.mov?raw=true) (1.3MB, .mov) - -### Features -* Works with bare UIViewController -* Works with UIViewController contained inside UINavigationController -* Works with UIViewController contained inside UINavigationController, contained inside UITabbarController -* Auto handling of modal frame size -* Auto handling of touch area for dismissal -* Resizable after presenting so that keyboard related interactions are possible -* Easy to understand and very small code base, only 2 files -* Trivial to implement as subclass -* Landscape support (not during presentation) -* Only use basic CAAnimation -* iPad support (experimental) -* Minimum iOS 5.0 (if you need 4.x support, use older commits before Jan 2013) - -### Optional parameters - -- animation duration -- parent alpha -- optional push-back -- shadow opacity -- disabling the cancel action -- transition style: slide up, fade - -Easily extend this to anything you would want to make configurable. Feel free to submit pull requests. - -### Installation / How to use -* Copy 4 files in `Source` folder to your project -* Add `QuartzCore.framework` to your project -* `#import "UIViewController+KNSemiModal.h"` in your ViewController -* Call `[self presentSemiModalView:myView]` -* Call `[self dismissSemiModalView]` either from parent/presenting or child/presented controller - -### Major contributors - -- [@yangmeyer](http://twitter.com/yangmeyer) -- [@dchohfi](https://github.com/dchohfi) - -### License - -In short: MIT aka Buy me coffee license [![](http://kentnguyen.com/KNCoffeeButton.png)](http://bit.ly/10KC2wr) - -UIViewController+KNSemiModal is licensed under MIT License -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. +add KNSemiModalTransitionStyleSlideDown option,and change animation with spring effect. \ No newline at end of file diff --git a/Source/._UIViewController+KNSemiModal.h b/Source/._UIViewController+KNSemiModal.h new file mode 100644 index 0000000..c893829 Binary files /dev/null and b/Source/._UIViewController+KNSemiModal.h differ diff --git a/Source/._UIViewController+KNSemiModal.m b/Source/._UIViewController+KNSemiModal.m new file mode 100644 index 0000000..c893829 Binary files /dev/null and b/Source/._UIViewController+KNSemiModal.m differ diff --git a/Source/UIViewController+KNSemiModal.h b/Source/UIViewController+KNSemiModal.h index 65bd8ab..10fb10d 100755 --- a/Source/UIViewController+KNSemiModal.h +++ b/Source/UIViewController+KNSemiModal.h @@ -5,7 +5,7 @@ // @interface NSObject (YMOptionsAndDefaults) - (void)ym_registerOptions:(NSDictionary *)options - defaults:(NSDictionary *)defaults; + defaults:(NSDictionary *)defaults; - (id)ym_optionOrDefaultForKey:(NSString*)optionKey; @end //================================================================================================== @@ -34,22 +34,23 @@ #define kSemiModalWasResizedNotification @"kSemiModalWasResizedNotification" extern const struct KNSemiModalOptionKeys { - __unsafe_unretained NSString *traverseParentHierarchy; // boxed BOOL. default is YES. - __unsafe_unretained NSString *pushParentBack; // boxed BOOL. default is YES. - __unsafe_unretained NSString *animationDuration; // boxed double, in seconds. default is 0.5. - __unsafe_unretained NSString *parentAlpha; // boxed float. lower is darker. default is 0.5. + __unsafe_unretained NSString *traverseParentHierarchy; // boxed BOOL. default is YES. + __unsafe_unretained NSString *pushParentBack; // boxed BOOL. default is YES. + __unsafe_unretained NSString *animationDuration; // boxed double, in seconds. default is 0.5. + __unsafe_unretained NSString *parentAlpha; // boxed float. lower is darker. default is 0.5. __unsafe_unretained NSString *parentScale; // boxed double default is 0.8 - __unsafe_unretained NSString *shadowOpacity; // default is 0.8 - __unsafe_unretained NSString *transitionStyle; // boxed NSNumber - one of the KNSemiModalTransitionStyle values. + __unsafe_unretained NSString *shadowOpacity; // default is 0.8 + __unsafe_unretained NSString *transitionStyle; // boxed NSNumber - one of the KNSemiModalTransitionStyle values. __unsafe_unretained NSString *disableCancel; // boxed BOOL. default is NO. __unsafe_unretained NSString *backgroundView; // UIView, custom background. } KNSemiModalOptionKeys; NS_ENUM(NSUInteger, KNSemiModalTransitionStyle) { - KNSemiModalTransitionStyleSlideUp, - KNSemiModalTransitionStyleFadeInOut, - KNSemiModalTransitionStyleFadeIn, - KNSemiModalTransitionStyleFadeOut, + KNSemiModalTransitionStyleSlideUp, + KNSemiModalTransitionStyleSlideDown, + KNSemiModalTransitionStyleFadeInOut, + KNSemiModalTransitionStyleFadeIn, + KNSemiModalTransitionStyleFadeOut, }; typedef void (^KNTransitionCompletionBlock)(void); @@ -64,13 +65,13 @@ typedef void (^KNTransitionCompletionBlock)(void); @param dismissBlock Is called when the user dismisses the semi-modal view by tapping the dimmed receiver view. */ -(void)presentSemiViewController:(UIViewController*)vc - withOptions:(NSDictionary*)options - completion:(KNTransitionCompletionBlock)completion - dismissBlock:(KNTransitionCompletionBlock)dismissBlock; + withOptions:(NSDictionary*)options + completion:(KNTransitionCompletionBlock)completion + dismissBlock:(KNTransitionCompletionBlock)dismissBlock; -(void)presentSemiView:(UIView*)view - withOptions:(NSDictionary*)options - completion:(KNTransitionCompletionBlock)completion; + withOptions:(NSDictionary*)options + completion:(KNTransitionCompletionBlock)completion; // Convenient overloading methods -(void)presentSemiViewController:(UIViewController*)vc; diff --git a/Source/UIViewController+KNSemiModal.m b/Source/UIViewController+KNSemiModal.m index 26421af..68ded25 100755 --- a/Source/UIViewController+KNSemiModal.m +++ b/Source/UIViewController+KNSemiModal.m @@ -11,13 +11,13 @@ #import const struct KNSemiModalOptionKeys KNSemiModalOptionKeys = { - .traverseParentHierarchy = @"KNSemiModalOptionTraverseParentHierarchy", - .pushParentBack = @"KNSemiModalOptionPushParentBack", - .animationDuration = @"KNSemiModalOptionAnimationDuration", - .parentAlpha = @"KNSemiModalOptionParentAlpha", + .traverseParentHierarchy = @"KNSemiModalOptionTraverseParentHierarchy", + .pushParentBack = @"KNSemiModalOptionPushParentBack", + .animationDuration = @"KNSemiModalOptionAnimationDuration", + .parentAlpha = @"KNSemiModalOptionParentAlpha", .parentScale = @"KNSemiModalOptionParentScale", - .shadowOpacity = @"KNSemiModalOptionShadowOpacity", - .transitionStyle = @"KNSemiModalTransitionStyle", + .shadowOpacity = @"KNSemiModalOptionShadowOpacity", + .transitionStyle = @"KNSemiModalTransitionStyle", .disableCancel = @"KNSemiModalOptionDisableCancel", .backgroundView = @"KNSemiModelOptionBackgroundView", }; @@ -38,14 +38,14 @@ -(CAAnimationGroup*)animationGroupForward:(BOOL)_forward; @implementation UIViewController (KNSemiModalInternal) -(UIViewController*)kn_parentTargetViewController { - UIViewController * target = self; - if ([[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.traverseParentHierarchy] boolValue]) { - // cover UINav & UITabbar as well - while (target.parentViewController != nil) { - target = target.parentViewController; - } - } - return target; + UIViewController * target = self; + if ([[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.traverseParentHierarchy] boolValue]) { + // cover UINav & UITabbar as well + while (target.parentViewController != nil) { + target = target.parentViewController; + } + } + return target; } -(UIView*)parentTarget { return [self kn_parentTargetViewController].view; @@ -54,16 +54,16 @@ -(UIView*)parentTarget { #pragma mark Options and defaults -(void)kn_registerDefaultsAndOptions:(NSDictionary*)options { - [self ym_registerOptions:options defaults:@{ - KNSemiModalOptionKeys.traverseParentHierarchy : @(YES), - KNSemiModalOptionKeys.pushParentBack : @(YES), - KNSemiModalOptionKeys.animationDuration : @(0.5), - KNSemiModalOptionKeys.parentAlpha : @(0.5), - KNSemiModalOptionKeys.parentScale : @(0.8), - KNSemiModalOptionKeys.shadowOpacity : @(0.8), - KNSemiModalOptionKeys.transitionStyle : @(KNSemiModalTransitionStyleSlideUp), - KNSemiModalOptionKeys.disableCancel : @(NO), - }]; + [self ym_registerOptions:options defaults:@{ + KNSemiModalOptionKeys.traverseParentHierarchy : @(YES), + KNSemiModalOptionKeys.pushParentBack : @(YES), + KNSemiModalOptionKeys.animationDuration : @(0.5), + KNSemiModalOptionKeys.parentAlpha : @(0.5), + KNSemiModalOptionKeys.parentScale : @(0.8), + KNSemiModalOptionKeys.shadowOpacity : @(0.8), + KNSemiModalOptionKeys.transitionStyle : @(KNSemiModalTransitionStyleSlideUp), + KNSemiModalOptionKeys.disableCancel : @(NO), + }]; } #pragma mark Push-back animation group @@ -94,7 +94,7 @@ -(CAAnimationGroup*)animationGroupForward:(BOOL)_forward { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"]; animation.toValue = [NSValue valueWithCATransform3D:t1]; - CFTimeInterval duration = [[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.animationDuration] doubleValue]; + CFTimeInterval duration = [[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.animationDuration] doubleValue]; animation.duration = duration/2; animation.fillMode = kCAFillModeForwards; animation.removedOnCompletion = NO; @@ -116,17 +116,17 @@ -(CAAnimationGroup*)animationGroupForward:(BOOL)_forward { } -(void)kn_interfaceOrientationDidChange:(NSNotification*)notification { - UIView *overlay = [[self parentTarget] viewWithTag:kSemiModalOverlayTag]; - [self kn_addOrUpdateParentScreenshotInView:overlay]; + UIView *overlay = [[self parentTarget] viewWithTag:kSemiModalOverlayTag]; + [self kn_addOrUpdateParentScreenshotInView:overlay]; } -(UIImageView*)kn_addOrUpdateParentScreenshotInView:(UIView*)screenshotContainer { - UIView *target = [self parentTarget]; - UIView *semiView = [target viewWithTag:kSemiModalModalViewTag]; - - screenshotContainer.hidden = YES; // screenshot without the overlay! - semiView.hidden = YES; - UIGraphicsBeginImageContextWithOptions(target.bounds.size, YES, [[UIScreen mainScreen] scale]); + UIView *target = [self parentTarget]; + UIView *semiView = [target viewWithTag:kSemiModalModalViewTag]; + + screenshotContainer.hidden = YES; // screenshot without the overlay! + semiView.hidden = YES; + UIGraphicsBeginImageContextWithOptions(target.bounds.size, YES, [[UIScreen mainScreen] scale]); if ([target respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) { [target drawViewHierarchyInRect:target.bounds afterScreenUpdates:YES]; } else { @@ -134,20 +134,20 @@ -(UIImageView*)kn_addOrUpdateParentScreenshotInView:(UIView*)screenshotContainer } UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - screenshotContainer.hidden = NO; - semiView.hidden = NO; - - UIImageView* screenshot = (id) [screenshotContainer viewWithTag:kSemiModalScreenshotTag]; - if (screenshot) { - screenshot.image = image; - } - else { - screenshot = [[UIImageView alloc] initWithImage:image]; - screenshot.tag = kSemiModalScreenshotTag; - screenshot.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [screenshotContainer addSubview:screenshot]; - } - return screenshot; + screenshotContainer.hidden = NO; + semiView.hidden = NO; + + UIImageView* screenshot = (id) [screenshotContainer viewWithTag:kSemiModalScreenshotTag]; + if (screenshot) { + screenshot.image = image; + } + else { + screenshot = [[UIImageView alloc] initWithImage:image]; + screenshot.tag = kSemiModalScreenshotTag; + screenshot.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [screenshotContainer addSubview:screenshot]; + } + return screenshot; } @end @@ -155,53 +155,53 @@ -(UIImageView*)kn_addOrUpdateParentScreenshotInView:(UIView*)screenshotContainer @implementation UIViewController (KNSemiModal) -(void)presentSemiViewController:(UIViewController*)vc { - [self presentSemiViewController:vc withOptions:nil completion:nil dismissBlock:nil]; + [self presentSemiViewController:vc withOptions:nil completion:nil dismissBlock:nil]; } -(void)presentSemiViewController:(UIViewController*)vc - withOptions:(NSDictionary*)options { + withOptions:(NSDictionary*)options { [self presentSemiViewController:vc withOptions:options completion:nil dismissBlock:nil]; } -(void)presentSemiViewController:(UIViewController*)vc - withOptions:(NSDictionary*)options - completion:(KNTransitionCompletionBlock)completion - dismissBlock:(KNTransitionCompletionBlock)dismissBlock { + withOptions:(NSDictionary*)options + completion:(KNTransitionCompletionBlock)completion + dismissBlock:(KNTransitionCompletionBlock)dismissBlock { [self kn_registerDefaultsAndOptions:options]; // re-registering is OK - UIViewController *targetParentVC = [self kn_parentTargetViewController]; - - // implement view controller containment for the semi-modal view controller - [targetParentVC addChildViewController:vc]; - if ([vc respondsToSelector:@selector(beginAppearanceTransition:animated:)]) { - [vc beginAppearanceTransition:YES animated:YES]; // iOS 6 - } - objc_setAssociatedObject(self, kSemiModalViewController, vc, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - objc_setAssociatedObject(self, kSemiModalDismissBlock, dismissBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); - [self presentSemiView:vc.view withOptions:options completion:^{ - [vc didMoveToParentViewController:targetParentVC]; - if ([vc respondsToSelector:@selector(endAppearanceTransition)]) { - [vc endAppearanceTransition]; // iOS 6 - } - if (completion) { - completion(); - } - }]; + UIViewController *targetParentVC = [self kn_parentTargetViewController]; + + // implement view controller containment for the semi-modal view controller + [targetParentVC addChildViewController:vc]; + if ([vc respondsToSelector:@selector(beginAppearanceTransition:animated:)]) { + [vc beginAppearanceTransition:YES animated:YES]; // iOS 6 + } + objc_setAssociatedObject(self, kSemiModalViewController, vc, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(self, kSemiModalDismissBlock, dismissBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); + [self presentSemiView:vc.view withOptions:options completion:^{ + [vc didMoveToParentViewController:targetParentVC]; + if ([vc respondsToSelector:@selector(endAppearanceTransition)]) { + [vc endAppearanceTransition]; // iOS 6 + } + if (completion) { + completion(); + } + }]; } -(void)presentSemiView:(UIView*)view { - [self presentSemiView:view withOptions:nil completion:nil]; + [self presentSemiView:view withOptions:nil completion:nil]; } -(void)presentSemiView:(UIView*)view withOptions:(NSDictionary*)options { - [self presentSemiView:view withOptions:options completion:nil]; + [self presentSemiView:view withOptions:options completion:nil]; } -(void)presentSemiView:(UIView*)view - withOptions:(NSDictionary*)options - completion:(KNTransitionCompletionBlock)completion { - [self kn_registerDefaultsAndOptions:options]; // re-registering is OK - UIView * target = [self parentTarget]; - + withOptions:(NSDictionary*)options + completion:(KNTransitionCompletionBlock)completion { + [self kn_registerDefaultsAndOptions:options]; // re-registering is OK + UIView * target = [self parentTarget]; + if (![target.subviews containsObject:view]) { // Set associative object objc_setAssociatedObject(view, kSemiModalPresentingViewController, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - + // Register for orientation changes, so we can update the presenting controller screenshot [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kn_interfaceOrientationDidChange:) @@ -218,7 +218,8 @@ -(void)presentSemiView:(UIView*)view // We center the view and mantain aspect ration semiViewFrame = CGRectMake((vf.size.width - view.frame.size.width) / 2.0, vf.size.height-semiViewHeight, view.frame.size.width, semiViewHeight); } else { - semiViewFrame = CGRectMake(0, vf.size.height-semiViewHeight, vf.size.width, semiViewHeight); + // semiViewFrame = CGRectMake(0, vf.size.height-semiViewHeight, vf.size.width, semiViewHeight); + semiViewFrame = CGRectMake(0, 0, vf.size.width, semiViewHeight); } CGRect overlayFrame = CGRectMake(0, 0, vf.size.width, vf.size.height-semiViewHeight); @@ -255,18 +256,23 @@ -(void)presentSemiView:(UIView*)view } // Begin overlay animation - if ([[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.pushParentBack] boolValue]) { - [ss.layer addAnimation:[self animationGroupForward:YES] forKey:@"pushedBackAnimation"]; - } - NSTimeInterval duration = [[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.animationDuration] doubleValue]; + if ([[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.pushParentBack] boolValue]) { + [ss.layer addAnimation:[self animationGroupForward:YES] forKey:@"pushedBackAnimation"]; + } + NSTimeInterval duration = [[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.animationDuration] doubleValue]; [UIView animateWithDuration:duration animations:^{ ss.alpha = [[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.parentAlpha] floatValue]; }]; // Present view animated - view.frame = (transitionStyle == KNSemiModalTransitionStyleSlideUp - ? CGRectOffset(semiViewFrame, 0, +semiViewHeight) - : semiViewFrame); + if(transitionStyle==KNSemiModalTransitionStyleSlideUp){ + view.frame = CGRectOffset(semiViewFrame, 0, +semiViewHeight); + } + + if(transitionStyle==KNSemiModalTransitionStyleSlideDown){ + view.frame = CGRectOffset(semiViewFrame, 0, -semiViewHeight); + } + if (transitionStyle == KNSemiModalTransitionStyleFadeIn || transitionStyle == KNSemiModalTransitionStyleFadeInOut) { view.alpha = 0.0; } @@ -287,10 +293,12 @@ -(void)presentSemiView:(UIView*)view view.layer.shouldRasterize = YES; view.layer.rasterizationScale = [[UIScreen mainScreen] scale]; - [UIView animateWithDuration:duration animations:^{ + [UIView animateWithDuration:duration delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:0 options:nil animations:^{ if (transitionStyle == KNSemiModalTransitionStyleSlideUp) { view.frame = semiViewFrame; - } else if (transitionStyle == KNSemiModalTransitionStyleFadeIn || transitionStyle == KNSemiModalTransitionStyleFadeInOut) { + } else if(transitionStyle == KNSemiModalTransitionStyleSlideDown){ + view.frame = semiViewFrame; + }else if (transitionStyle == KNSemiModalTransitionStyleFadeIn || transitionStyle == KNSemiModalTransitionStyleFadeInOut) { view.alpha = 1.0; } } completion:^(BOOL finished) { @@ -301,6 +309,24 @@ -(void)presentSemiView:(UIView*)view completion(); } }]; + + // [UIView animateWithDuration:duration animations:^{ + // if (transitionStyle == KNSemiModalTransitionStyleSlideUp) { + // view.frame = semiViewFrame; + // } else if(transitionStyle == KNSemiModalTransitionStyleSlideDown){ + // view.frame = semiViewFrame; + // }else if (transitionStyle == KNSemiModalTransitionStyleFadeIn || transitionStyle == KNSemiModalTransitionStyleFadeInOut) { + // view.alpha = 1.0; + // } + // } completion:^(BOOL finished) { + // if (!finished) return; + // [[NSNotificationCenter defaultCenter] postNotificationName:kSemiModalDidShowNotification + // object:self]; + // if (completion) { + // completion(); + // } + // }]; + } } -(void)updateBackground{ @@ -309,7 +335,7 @@ -(void)updateBackground{ [self kn_addOrUpdateParentScreenshotInView:overlay]; } -(void)dismissSemiModalView { - [self dismissSemiModalViewWithCompletion:nil]; + [self dismissSemiModalViewWithCompletion:nil]; } -(void)dismissSemiModalViewWithCompletion:(void (^)(void))completion { @@ -325,22 +351,22 @@ -(void)dismissSemiModalViewWithCompletion:(void (^)(void))completion { [presentingController dismissSemiModalViewWithCompletion:completion]; return; } - + // Correct target for dismissal UIView * target = [self parentTarget]; UIView * modal = [target viewWithTag:kSemiModalModalViewTag]; UIView * overlay = [target viewWithTag:kSemiModalOverlayTag]; - NSUInteger transitionStyle = [[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.transitionStyle] unsignedIntegerValue]; - NSTimeInterval duration = [[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.animationDuration] doubleValue]; - UIViewController *vc = objc_getAssociatedObject(self, kSemiModalViewController); - KNTransitionCompletionBlock dismissBlock = objc_getAssociatedObject(self, kSemiModalDismissBlock); - - // Child controller containment - [vc willMoveToParentViewController:nil]; - if ([vc respondsToSelector:@selector(beginAppearanceTransition:animated:)]) { - [vc beginAppearanceTransition:NO animated:YES]; // iOS 6 - } - + NSUInteger transitionStyle = [[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.transitionStyle] unsignedIntegerValue]; + NSTimeInterval duration = [[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.animationDuration] doubleValue]; + UIViewController *vc = objc_getAssociatedObject(self, kSemiModalViewController); + KNTransitionCompletionBlock dismissBlock = objc_getAssociatedObject(self, kSemiModalDismissBlock); + + // Child controller containment + [vc willMoveToParentViewController:nil]; + if ([vc respondsToSelector:@selector(beginAppearanceTransition:animated:)]) { + [vc beginAppearanceTransition:NO animated:YES]; // iOS 6 + } + [UIView animateWithDuration:duration animations:^{ if (transitionStyle == KNSemiModalTransitionStyleSlideUp) { if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad){ @@ -349,7 +375,14 @@ -(void)dismissSemiModalViewWithCompletion:(void (^)(void))completion { } else { modal.frame = CGRectMake(0, target.bounds.size.height, modal.frame.size.width, modal.frame.size.height); } - } else if (transitionStyle == KNSemiModalTransitionStyleFadeOut || transitionStyle == KNSemiModalTransitionStyleFadeInOut) { + } if (transitionStyle == KNSemiModalTransitionStyleSlideDown) { + if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad){ + // As the view is centered, we perform a vertical translation + modal.frame = CGRectMake((target.bounds.size.width - modal.frame.size.width) / 2.0, target.bounds.size.height, modal.frame.size.width, modal.frame.size.height); + } else { + modal.frame = CGRectMake(0,-modal.frame.size.height, modal.frame.size.width, modal.frame.size.height); + } + }else if (transitionStyle == KNSemiModalTransitionStyleFadeOut || transitionStyle == KNSemiModalTransitionStyleFadeInOut) { modal.alpha = 0.0; } } completion:^(BOOL finished) { @@ -374,9 +407,9 @@ -(void)dismissSemiModalViewWithCompletion:(void (^)(void))completion { // Begin overlay animation UIImageView * ss = (UIImageView*)[overlay.subviews objectAtIndex:0]; - if ([[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.pushParentBack] boolValue]) { - [ss.layer addAnimation:[self animationGroupForward:NO] forKey:@"bringForwardAnimation"]; - } + if ([[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.pushParentBack] boolValue]) { + [ss.layer addAnimation:[self animationGroupForward:NO] forKey:@"bringForwardAnimation"]; + } [UIView animateWithDuration:duration animations:^{ ss.alpha = 1; } completion:^(BOOL finished) { @@ -401,8 +434,8 @@ - (void)resizeSemiView:(CGSize)newSize { UIButton * button = (UIButton*)[overlay viewWithTag:kSemiModalDismissButtonTag]; CGRect bf = button.frame; bf.size.height = overlay.frame.size.height - newSize.height; - NSTimeInterval duration = [[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.animationDuration] doubleValue]; - [UIView animateWithDuration:duration animations:^{ + NSTimeInterval duration = [[self ym_optionOrDefaultForKey:KNSemiModalOptionKeys.animationDuration] doubleValue]; + [UIView animateWithDuration:duration animations:^{ modal.frame = mf; button.frame = bf; } completion:^(BOOL finished) { @@ -430,18 +463,18 @@ @implementation NSObject (YMOptionsAndDefaults) static char const * const kYMStandardDefaultsTableName = "YMStandardDefaultsTableName"; - (void)ym_registerOptions:(NSDictionary *)options - defaults:(NSDictionary *)defaults + defaults:(NSDictionary *)defaults { - objc_setAssociatedObject(self, kYMStandardOptionsTableName, options, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - objc_setAssociatedObject(self, kYMStandardDefaultsTableName, defaults, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(self, kYMStandardOptionsTableName, options, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(self, kYMStandardDefaultsTableName, defaults, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (id)ym_optionOrDefaultForKey:(NSString*)optionKey { - NSDictionary *options = objc_getAssociatedObject(self, kYMStandardOptionsTableName); - NSDictionary *defaults = objc_getAssociatedObject(self, kYMStandardDefaultsTableName); - NSAssert(defaults, @"Defaults must have been set when accessing options."); - return options[optionKey] ?: defaults[optionKey]; + NSDictionary *options = objc_getAssociatedObject(self, kYMStandardOptionsTableName); + NSDictionary *defaults = objc_getAssociatedObject(self, kYMStandardDefaultsTableName); + NSAssert(defaults, @"Defaults must have been set when accessing options."); + return options[optionKey] ?: defaults[optionKey]; } @end