Skip to content

Commit

Permalink
Merge pull request github#136 from maxgoedjen/feature-tuinavigationco…
Browse files Browse the repository at this point in the history
…ntroller

Adding TUINavigationController
  • Loading branch information
CodaFi committed Nov 14, 2012
2 parents 537d24f + 4945abc commit a0c44be
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 1 deletion.
12 changes: 11 additions & 1 deletion TwUI.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
48A10E8415B7769A007F9EE3 /* TUILayoutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 48A10E8015B7769A007F9EE3 /* TUILayoutManager.m */; };
48A10E8915B778E8007F9EE3 /* TUIView+Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = 48A10E8715B778E8007F9EE3 /* TUIView+Layout.m */; };
48A10E8B15B77A46007F9EE3 /* TUIView+Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 48A10E8A15B77A46007F9EE3 /* TUIView+Layout.h */; settings = {ATTRIBUTES = (Public, ); }; };
5000874016524B1C0067ED42 /* TUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5000873F16524B1C0067ED42 /* TUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; };
5000874916524B1F0067ED42 /* TUINavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5000874816524B1F0067ED42 /* TUINavigationController.m */; };
5000874A1652C4380067ED42 /* TUINavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5000874816524B1F0067ED42 /* TUINavigationController.m */; };
5E6ECEB313BE791600109598 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5EE9839C13BE7650005F430D /* ApplicationServices.framework */; };
5E6ECEB413BE791600109598 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB5E31B613BE6F49004B7899 /* QuartzCore.framework */; };
5E6ECEB613BE791C00109598 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5EE9839C13BE7650005F430D /* ApplicationServices.framework */; };
Expand Down Expand Up @@ -436,6 +439,8 @@
48A10E8015B7769A007F9EE3 /* TUILayoutManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TUILayoutManager.m; sourceTree = "<group>"; };
48A10E8715B778E8007F9EE3 /* TUIView+Layout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "TUIView+Layout.m"; sourceTree = "<group>"; };
48A10E8A15B77A46007F9EE3 /* TUIView+Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TUIView+Layout.h"; sourceTree = "<group>"; };
5000873F16524B1C0067ED42 /* TUINavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TUINavigationController.h; sourceTree = "<group>"; };
5000874816524B1F0067ED42 /* TUINavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TUINavigationController.m; sourceTree = "<group>"; };
48A6234F162C63E900DFA443 /* TUIScrollView+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TUIScrollView+Private.h"; sourceTree = "<group>"; };
5EE9839C13BE7650005F430D /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = System/Library/Frameworks/ApplicationServices.framework; sourceTree = SDKROOT; };
5EE983B713BE7809005F430D /* libtwui.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtwui.a; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -795,6 +800,8 @@
48A10E7E15B7769A007F9EE3 /* TUILayoutConstraint.m */,
48A10E7F15B7769A007F9EE3 /* TUILayoutManager.h */,
48A10E8015B7769A007F9EE3 /* TUILayoutManager.m */,
5000873F16524B1C0067ED42 /* TUINavigationController.h */,
5000874816524B1F0067ED42 /* TUINavigationController.m */,
8819794A13E26E5800AA39EB /* TUINSView+Accessibility.h */,
8819794B13E26E5800AA39EB /* TUINSView+Accessibility.m */,
CBB74C5E13BE6E1900C85CB5 /* TUINSView+Hyperfocus.h */,
Expand Down Expand Up @@ -847,8 +854,8 @@
CBB74C7913BE6E1900C85CB5 /* TUITextRenderer+Event.h */,
CBB74C7A13BE6E1900C85CB5 /* TUITextRenderer+Event.m */,
CBB74C7B13BE6E1900C85CB5 /* TUITextRenderer+KeyBindings.m */,
CBB74C7C13BE6E1900C85CB5 /* TUITextRenderer.h */,
48373DF4160EAE9400322CA7 /* TUITextRenderer+Private.h */,
CBB74C7C13BE6E1900C85CB5 /* TUITextRenderer.h */,
CBB74C7D13BE6E1900C85CB5 /* TUITextRenderer.m */,
CBB74C7E13BE6E1900C85CB5 /* TUITextView.h */,
CBB74C7F13BE6E1900C85CB5 /* TUITextView.m */,
Expand Down Expand Up @@ -997,6 +1004,7 @@
D0C7651615B61E5A00E7AC2C /* TUIBridgedScrollView.h in Headers */,
D0C7653315B624D900E7AC2C /* NSView+TUIExtensions.h in Headers */,
D0C7654615B626E200E7AC2C /* TUIView+TUIBridgedView.h in Headers */,
5000874016524B1C0067ED42 /* TUINavigationController.h in Headers */,
D0C7655215B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.h in Headers */,
D0C7655D15B6297300E7AC2C /* NSClipView+TUIExtensions.h in Headers */,
D0C7656315B6297300E7AC2C /* NSScrollView+TUIExtensions.h in Headers */,
Expand Down Expand Up @@ -1324,6 +1332,7 @@
D05D23A515BF7239000ED14F /* NSImage+TUIExtensions.m in Sources */,
D0EA12F615C34FEA00FAA603 /* NSColor+TUIExtensions.m in Sources */,
488A5838162FBE9B006CBF8B /* TUITableViewController.m in Sources */,
5000874A1652C4380067ED42 /* TUINavigationController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1398,6 +1407,7 @@
887C227C15C1C7BB006EC31D /* NSFont+TUIExtensions.m in Sources */,
D0EA12F415C34FEA00FAA603 /* NSColor+TUIExtensions.m in Sources */,
488A5836162FBE9B006CBF8B /* TUITableViewController.m in Sources */,
5000874916524B1F0067ED42 /* TUINavigationController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
1 change: 1 addition & 0 deletions lib/UIKit/TUIKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#import "TUIImageView.h"
#import "TUILabel.h"
#import "TUILayoutConstraint.h"
#import "TUINavigationController.h"
#import "TUINSView.h"
#import "TUINSView+Hyperfocus.h"
#import "TUINSView+NSTextInputClient.h"
Expand Down
27 changes: 27 additions & 0 deletions lib/UIKit/TUINavigationController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// TUINavigationController.h
// TwUI
//
// Created by Max Goedjen on 11/12/12.
//
//

#import <Foundation/Foundation.h>
#import "TUIViewController.h"

@interface TUINavigationController : TUIViewController

@property (nonatomic, readonly) TUIViewController *topViewController;
@property (nonatomic, readonly) NSArray *viewControllers;

- (id)initWithRootViewController:(TUIViewController *)viewController;

- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated;

- (void)pushViewController:(TUIViewController *)viewController animated:(BOOL)animated;
- (TUIViewController *)popViewControlerAnimated:(BOOL)animated;
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated;
- (NSArray *)popToViewController:(TUIViewController *)viewController animated:(BOOL)animated;


@end
179 changes: 179 additions & 0 deletions lib/UIKit/TUINavigationController.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//
// TUINavigationController.m
// TwUI
//
// Created by Max Goedjen on 11/12/12.
//
//

#import "TUINavigationController.h"
#import "TUIView.h"

@interface TUINavigationController ()

@property (nonatomic) NSMutableArray *stack;

@end

static CGFloat const TUINavigationControllerAnimationDuration = 0.5f;

@implementation TUINavigationController

- (id)initWithRootViewController:(TUIViewController *)viewController {
self = [super init];
if (self) {
_stack = [@[] mutableCopy];
[_stack addObject:viewController];
self.view.clipsToBounds = YES;
}
return self;
}

- (void)loadView {
self.view = [[TUIView alloc] initWithFrame:CGRectZero];
self.view.backgroundColor = [NSColor lightGrayColor];

TUIViewController *visible = [self topViewController];
[visible viewWillAppear:NO];
[self.view addSubview:visible.view];
visible.view.frame = self.view.bounds;
visible.view.autoresizingMask = TUIViewAutoresizingFlexibleSize;
[visible viewDidAppear:YES];

}

#pragma mark - Properties

- (NSArray *)viewControllers {
return [NSArray arrayWithArray:_stack];
}

- (TUIViewController *)topViewController {
return [_stack lastObject];
}

#pragma mark - Methods

- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated {
CGFloat duration = animated ? TUINavigationControllerAnimationDuration : 0;

TUIViewController *viewController = [viewControllers lastObject];
BOOL containedAlready = ([_stack containsObject:viewController]);

[CATransaction begin];
//Push if it's not in the stack, pop back if it is
[self.view addSubview:viewController.view];
viewController.view.frame = containedAlready ? TUINavigationOffscreenLeftFrame(self.view.bounds) : TUINavigationOffscreenRightFrame(self.view.bounds);
[CATransaction flush];
[CATransaction commit];

TUIViewController *last = [self topViewController];

[_stack removeAllObjects];
[_stack addObjectsFromArray:viewControllers];

[TUIView animateWithDuration:duration animations:^{
last.view.frame = containedAlready ? TUINavigationOffscreenRightFrame(self.view.bounds) : TUINavigationOffscreenLeftFrame(self.view.bounds);
viewController.view.frame = self.view.bounds;
} completion:^(BOOL finished) {
[last.view removeFromSuperview];
[viewController viewDidAppear:animated];
[last viewDidDisappear:animated];
}];
}

- (void)pushViewController:(TUIViewController *)viewController animated:(BOOL)animated {

TUIViewController *last = [self topViewController];
[_stack addObject:viewController];
CGFloat duration = animated ? TUINavigationControllerAnimationDuration : 0;

[last viewWillDisappear:animated];
[viewController viewWillAppear:animated];

[self.view addSubview:viewController.view];

//Make sure the app draws the frame offscreen instead of just 'popping' it in
[CATransaction begin];
viewController.view.frame = TUINavigationOffscreenRightFrame(self.view.bounds);
[CATransaction flush];
[CATransaction commit];

[TUIView animateWithDuration:duration animations:^{
last.view.frame = TUINavigationOffscreenLeftFrame(self.view.bounds);
viewController.view.frame = self.view.bounds;
} completion:^(BOOL finished) {
[last.view removeFromSuperview];
[viewController viewDidAppear:animated];
[last viewDidDisappear:animated];
}];
}

- (TUIViewController *)popViewControlerAnimated:(BOOL)animated {
if ([_stack count] <= 1) {
NSLog(@"Not enough view controllers on stack to pop");
return nil;
}
TUIViewController *popped = [_stack lastObject];
[self popToViewController:[_stack objectAtIndex:([_stack count] - 2)] animated:animated];
return popped;
}

- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated {
if ([[self topViewController] isEqual:[_stack objectAtIndex:0]] == YES) {
return @[];
}
return [self popToViewController:[_stack objectAtIndex:0] animated:animated];
}

- (NSArray *)popToViewController:(TUIViewController *)viewController animated:(BOOL)animated {
if ([_stack containsObject:viewController] == NO) {
NSLog(@"View controller %@ is not in stack", viewController);
return @[];
}

TUIViewController *last = [_stack lastObject];

NSMutableArray *popped = [@[] mutableCopy];
while ([viewController isEqual:[_stack lastObject]] == NO) {
[popped addObject:[_stack lastObject]];
[_stack removeLastObject];
}


[self.view addSubview:viewController.view];
viewController.view.frame = TUINavigationOffscreenLeftFrame(self.view.bounds);

CGFloat duration = animated ? TUINavigationControllerAnimationDuration : 0;

[last viewWillDisappear:animated];
[viewController viewWillAppear:animated];

[TUIView animateWithDuration:duration animations:^{
last.view.frame = TUINavigationOffscreenRightFrame(self.view.bounds);
viewController.view.frame = self.view.bounds;
} completion:^(BOOL finished) {
[last.view removeFromSuperview];
[viewController viewDidAppear:animated];
[last viewDidDisappear:animated];
}];


return popped;
}

#pragma mark - Private

static inline CGRect TUINavigationOffscreenLeftFrame(CGRect bounds) {
CGRect offscreenLeft = bounds;
offscreenLeft.origin.x -= bounds.size.width;
return offscreenLeft;
}

static inline CGRect TUINavigationOffscreenRightFrame(CGRect bounds) {
CGRect offscreenRight = bounds;
offscreenRight.origin.x += bounds.size.width;
return offscreenRight;
}

@end

0 comments on commit a0c44be

Please sign in to comment.