Skip to content

Commit

Permalink
code reworked. custom transition animation. storyboard migrated to Xc…
Browse files Browse the repository at this point in the history
…ode 5.
  • Loading branch information
smolin_in committed Dec 31, 2013
1 parent a9c8457 commit 7dffeb0
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 115 deletions.
6 changes: 5 additions & 1 deletion EmbeddedSwapping/ContainerViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
// Copyright (c) 2012 Sandmoose Software. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface ContainerViewController : UIViewController

- (void)swapViewControllers;
@property (nonatomic, strong, readonly) UIViewController* currentController;

@property (nonatomic, strong) void(^animationBlock)(UIViewController* container, UIViewController* fromViewController, UIViewController* toViewController);

@end
110 changes: 42 additions & 68 deletions EmbeddedSwapping/ContainerViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,93 +8,67 @@
//

#import "ContainerViewController.h"
#import "FirstViewController.h"
#import "SecondViewController.h"

#define SegueIdentifierFirst @"embedFirst"
#define SegueIdentifierSecond @"embedSecond"

@interface ContainerViewController ()

@property (strong, nonatomic) NSString *currentSegueIdentifier;
@property (strong, nonatomic) FirstViewController *firstViewController;
@property (strong, nonatomic) SecondViewController *secondViewController;
@property (assign, nonatomic) BOOL transitionInProgress;
@interface ContainerViewController () {
dispatch_queue_t serialTransitionQueue;
}

@end

@implementation ContainerViewController

- (void)viewDidLoad
{
[super viewDidLoad];
@synthesize currentController=_currentController;
@synthesize animationBlock=_animationBlock;

self.transitionInProgress = NO;
self.currentSegueIdentifier = SegueIdentifierFirst;
[self performSegueWithIdentifier:self.currentSegueIdentifier sender:nil];
}
-(id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
_animationBlock = ^void(UIViewController* container, UIViewController* fromViewController, UIViewController* toViewController) {
// no animation by default
[fromViewController removeFromParentViewController];
[container.view addSubview:toViewController.view];

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Instead of creating new VCs on each seque we want to hang on to existing
// instances if we have it. Remove the second condition of the following
// two if statements to get new VC instances instead.
if (([segue.identifier isEqualToString:SegueIdentifierFirst]) && !self.firstViewController) {
self.firstViewController = segue.destinationViewController;
}
[toViewController didMoveToParentViewController:container];
};

if (([segue.identifier isEqualToString:SegueIdentifierSecond]) && !self.secondViewController) {
self.secondViewController = segue.destinationViewController;
}
_currentController = nil;

// If we're going to the first view controller.
if ([segue.identifier isEqualToString:SegueIdentifierFirst]) {
// If this is not the first time we're loading this.
if (self.childViewControllers.count > 0) {
[self swapFromViewController:[self.childViewControllers objectAtIndex:0] toViewController:self.firstViewController];
}
else {
// If this is the very first time we're loading this we need to do
// an initial load and not a swap.
[self addChildViewController:segue.destinationViewController];
UIView* destView = ((UIViewController *)segue.destinationViewController).view;
destView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
destView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
[self.view addSubview:destView];
[segue.destinationViewController didMoveToParentViewController:self];
}
}
// By definition the second view controller will always be swapped with the
// first one.
else if ([segue.identifier isEqualToString:SegueIdentifierSecond]) {
[self swapFromViewController:[self.childViewControllers objectAtIndex:0] toViewController:self.secondViewController];
serialTransitionQueue = dispatch_queue_create("com.EmbeddedSwapping.queue", DISPATCH_QUEUE_SERIAL);
}

return self;
}

- (void)swapFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
toViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
toViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
UIViewController* destController = segue.destinationViewController;
UIView* destView = destController.view;

[fromViewController willMoveToParentViewController:nil];
[self addChildViewController:toViewController];
destView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
destView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);

[self transitionFromViewController:fromViewController toViewController:toViewController duration:1.0 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:^(BOOL finished) {
[fromViewController removeFromParentViewController];
[toViewController didMoveToParentViewController:self];
self.transitionInProgress = NO;
}];
}
if (self.currentController == nil) {
[destController willMoveToParentViewController:self];

- (void)swapViewControllers
{
if (self.transitionInProgress) {
return;
[self addChildViewController:destController];
[self.view addSubview:destView];

[destController didMoveToParentViewController:self];
} else {
[self moveFromViewController:self.currentController toViewController:destController];
}

self.transitionInProgress = YES;
self.currentSegueIdentifier = ([self.currentSegueIdentifier isEqualToString:SegueIdentifierFirst]) ? SegueIdentifierSecond : SegueIdentifierFirst;
[self performSegueWithIdentifier:self.currentSegueIdentifier sender:nil];
_currentController = destController;
}

- (void)moveFromViewController:(UIViewController*)from toViewController:(UIViewController*)to {
dispatch_async(serialTransitionQueue, ^(void){
dispatch_sync(dispatch_get_main_queue(), ^(void){
[to willMoveToParentViewController:self];

[self addChildViewController:to];
self.animationBlock(self, from, to);
});
});
}

@end
26 changes: 21 additions & 5 deletions EmbeddedSwapping/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,40 @@

#import "ViewController.h"
#import "ContainerViewController.h"
#import "FirstViewController.h"
#import "SecondViewController.h"

static NSString* const firstControllerSegueIdentifier = @"embedFirst";
static NSString* const secondControllerSegueIdentifier = @"embedSecond";

@interface ViewController ()
@property (nonatomic, weak) ContainerViewController *containerViewController;

- (IBAction)swapButtonPressed:(id)sender;

@end

@implementation ViewController

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"embedContainer"]) {
self.containerViewController = segue.destinationViewController;

self.containerViewController.animationBlock = ^void(UIViewController* container, UIViewController* fromViewController, UIViewController* toViewController) {
[container transitionFromViewController:fromViewController toViewController:toViewController duration:1.0 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:^(BOOL finished) {
[fromViewController removeFromParentViewController];
[toViewController didMoveToParentViewController:self];
}];
};
}
}

- (IBAction)swapButtonPressed:(id)sender
{
[self.containerViewController swapViewControllers];
- (IBAction)swapButtonPressed:(id)sender {
if ([self.containerViewController.currentController isKindOfClass:[FirstViewController class]]) {
[self.containerViewController performSegueWithIdentifier:secondControllerSegueIdentifier sender:self];
} else {
[self.containerViewController performSegueWithIdentifier:firstControllerSegueIdentifier sender:self];
}
}

@end
Loading

0 comments on commit 7dffeb0

Please sign in to comment.