Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Example/PSStackedViewExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
1F82478114EB76AD00773D9B /* popIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 1F82478014EB76AD00773D9B /* popIcon.png */; };
1FEE7FF814C8E23200424F88 /* PSStackedViewSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FEE7FF714C8E23200424F88 /* PSStackedViewSegue.m */; };
3798AD7B13E0B299004C1E33 /* error.png in Resources */ = {isa = PBXBuildFile; fileRef = 3798AD7413E0B299004C1E33 /* error.png */; };
3798AD7D13E0B299004C1E33 /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = 3798AD7613E0B299004C1E33 /* [email protected] */; };
Expand Down Expand Up @@ -39,6 +40,7 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
1F82478014EB76AD00773D9B /* popIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = popIcon.png; sourceTree = "<group>"; };
1FEE7FF614C8E23200424F88 /* PSStackedViewSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PSStackedViewSegue.h; path = ../../PSStackedView/PSStackedViewSegue.h; sourceTree = "<group>"; };
1FEE7FF714C8E23200424F88 /* PSStackedViewSegue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PSStackedViewSegue.m; path = ../../PSStackedView/PSStackedViewSegue.m; sourceTree = "<group>"; };
3798AD7413E0B299004C1E33 /* error.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = error.png; sourceTree = "<group>"; };
Expand Down Expand Up @@ -209,6 +211,7 @@
7884393E13CEF82D00D18A56 /* Images */ = {
isa = PBXGroup;
children = (
1F82478014EB76AD00773D9B /* popIcon.png */,
3798AD7313E0B299004C1E33 /* error */,
3798AD7713E0B299004C1E33 /* NewGlow */,
78BA6A1313CF05C200DDA16E /* 08-chat.png */,
Expand Down Expand Up @@ -283,6 +286,7 @@
3798AD7D13E0B299004C1E33 /* [email protected] in Resources */,
3798AD7E13E0B299004C1E33 /* NewGlow.png in Resources */,
3798AD8013E0B299004C1E33 /* [email protected] in Resources */,
1F82478114EB76AD00773D9B /* popIcon.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
3 changes: 3 additions & 0 deletions Example/StackedViewKitExample/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
// set root controller as stack controller
ExampleMenuRootController *menuController = [[ExampleMenuRootController alloc] init];
self.stackController = [[PSStackedViewController alloc] initWithRootViewController:menuController];
self.stackController.enablePopOffOnDragRight = YES;
self.stackController.popOffType = SVPopOptionAllButFirst;
self.stackController.delegate = menuController;
self.window.rootViewController = self.stackController;
[self.window makeKeyAndVisible];

Expand Down
4 changes: 3 additions & 1 deletion Example/StackedViewKitExample/ExampleMenuRootController.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@

#import <UIKit/UIKit.h>

@interface ExampleMenuRootController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
@interface ExampleMenuRootController : UIViewController <UITableViewDataSource, UITableViewDelegate, PSStackedViewDelegate> {
UITableView *menuTable_;
UIImageView *popIconLeft_;
UIImageView *popIconRight_;
NSArray *cellContents_;
}

Expand Down
53 changes: 53 additions & 0 deletions Example/StackedViewKitExample/ExampleMenuRootController.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,16 @@
@interface ExampleMenuRootController()
@property (nonatomic, strong) UITableView *menuTable;
@property (nonatomic, strong) NSArray *cellContents;
@property (nonatomic, strong) UIImageView *popIconLeft;
@property (nonatomic, strong) UIImageView *popIconRight;
@end

@implementation ExampleMenuRootController

@synthesize menuTable = menuTable_;
@synthesize cellContents = cellContents_;
@synthesize popIconLeft = popIconLeft_;
@synthesize popIconRight = popIconRight_;

///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - NSObject
Expand Down Expand Up @@ -69,6 +73,16 @@ - (void)viewDidLoad {
self.menuTable.dataSource = self;
[self.view addSubview:self.menuTable];
[self.menuTable reloadData];

self.popIconLeft = [[UIImageView alloc] initWithFrame:CGRectMake(225, 482, 50, 70)];
self.popIconLeft.image = [UIImage imageNamed:@"popIcon.png"];
self.popIconLeft.alpha = 0.0;
[self.view addSubview:self.popIconLeft];

self.popIconRight = [[UIImageView alloc] initWithFrame:CGRectMake(245, 502, 50, 70)];
self.popIconRight.image = [UIImage imageNamed:@"popIcon.png"];
self.popIconRight.alpha = 0.0;
[self.view addSubview:self.popIconRight];
}

///////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -145,4 +159,43 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
}
}

/// PSStackedViewDelegate methods

- (void)stackedViewDidStartDragging:(PSStackedViewController *)stackedView {
if([stackedView.viewControllers count] > 1) {
[UIView animateWithDuration:0.2 animations:^(void) {
self.popIconLeft.alpha = 1.0;
self.popIconRight.alpha = 1.0;
}];
}
}

- (void)stackedViewDidStopDragging:(PSStackedViewController *)stackedView {
[UIView animateWithDuration:0.2 animations:^(void) {
self.popIconLeft.alpha = 0.0;
self.popIconRight.alpha = 0.0;
self.popIconRight.transform = CGAffineTransformIdentity;
}];
}

-(void)stackedView:(PSStackedViewController *)stackedView WillPopViewControllers:(NSArray *)controllers {
if([controllers count] > 0) {
[UIView animateWithDuration:0.2 animations:^(void) {
self.popIconRight.alpha = 0.5;
CGAffineTransform trans = CGAffineTransformMakeTranslation(40, 10);
trans = CGAffineTransformRotate(trans, M_PI/4);
self.popIconRight.transform = trans;
}];
}
}

- (void)stackedView:(PSStackedViewController *)stackedView WillNotPopViewControllers:(NSArray *)controllers {
if([controllers count] > 0) {
[UIView animateWithDuration:0.2 animations:^(void) {
self.popIconRight.alpha = 1.0;
self.popIconRight.transform = CGAffineTransformIdentity;
}];
}
}

@end
Binary file added Example/StackedViewKitExample/Images/popIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 17 additions & 1 deletion PSStackedView/PSStackedViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@
enum {
SVSnapOptionNearest,
SVSnapOptionLeft,
SVSnapOptionRight
SVSnapOptionRight,
SVSnapOptionPopRight
} typedef PSSVSnapOption;

enum {
SVPopOptionAllButFirst,
SVPopOptionAll,
SVPopOptionTop
} typedef PSSVPopOption;

/// StackController hosing a backside rootViewController and the stacked controllers
@interface PSStackedViewController : UIViewController

Expand Down Expand Up @@ -111,6 +118,15 @@ enum {
/// Property to disable bounces
@property(nonatomic, assign) BOOL enableBounces;

/// Property to enable poping off all of the stack views except the first when dragged past a specified amount
@property(nonatomic, assign) BOOL enablePopOffOnDragRight;

/// Property to determine the type of pop off action that will be taken when entire stack is dragged to the right
@property(nonatomic, assign) PSSVPopOption popOffType;

/// Property to determine the distance the stack has to be dragged to the right to trigger popOff
@property(nonatomic, assign) NSInteger popOffDragDistance;

/// left inset thats always visible. Defaults to 60.
@property(nonatomic, assign) NSUInteger leftInset;
/// animate setting of the left inset that is always visible
Expand Down
80 changes: 78 additions & 2 deletions PSStackedView/PSStackedViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define kPSSVStackAnimationPopDuration kPSSVStackAnimationSpeedModifier * 0.25f
#define kPSSVMaxSnapOverOffset 20
#define kPSSVAssociatedBaseViewControllerKey @"kPSSVAssociatedBaseViewController"
#define kPSSVDefaultPopOffDragDistance 150

// reduces alpha over overlapped view controllers. 1.f would totally black-out on complete overlay
#define kAlphaReductRatio 10.f
Expand All @@ -35,11 +36,18 @@ @interface PSStackedViewController() <UIGestureRecognizerDelegate> {
BOOL lastDragDividedOne_;
NSInteger lastVisibleIndexBeforeRotation_;
BOOL enableBounces_;
BOOL enablePopOffOnDragRight_;
PSSVPopOption popOffType_;
NSInteger popOffDragDistance_;
struct {
unsigned int delegateWillInsertViewController:1;
unsigned int delegateDidInsertViewController:1;
unsigned int delegateWillRemoveViewController:1;
unsigned int delegateDidRemoveViewController:1;
unsigned int delegateDidRemoveViewController:1;
unsigned int delegateDidStartDragging:1;
unsigned int delegateDidStopDragging:1;
unsigned int delegateWillPopViewControllers:1;
unsigned int delegateWillNotPopViewControllers:1;
}delegateFlags_;
}
@property(nonatomic, strong) UIViewController *rootViewController;
Expand All @@ -60,6 +68,9 @@ @implementation PSStackedViewController
@synthesize delegate = delegate_;
@synthesize reduceAnimations = reduceAnimations_;
@synthesize enableBounces = enableBounces_;
@synthesize enablePopOffOnDragRight = enablePopOffOnDragRight_;
@synthesize popOffType = popOffType_;
@synthesize popOffDragDistance = popOffDragDistance_;
@dynamic firstVisibleIndex;

#ifdef ALLOW_SWIZZLING_NAVIGATIONCONTROLLER
Expand All @@ -79,6 +90,7 @@ - (id)initWithRootViewController:(UIViewController *)rootViewController; {
// set some reasonble defaults
leftInset_ = 60;
largeLeftInset_ = 200;
popOffDragDistance_ = kPSSVDefaultPopOffDragDistance;

// add a gesture recognizer to detect dragging to the guest controllers
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanFrom:)];
Expand Down Expand Up @@ -123,6 +135,10 @@ - (void)setDelegate:(id<PSStackedViewDelegate>)delegate {
delegateFlags_.delegateDidInsertViewController = [delegate respondsToSelector:@selector(stackedView:didInsertViewController:)];
delegateFlags_.delegateWillRemoveViewController = [delegate respondsToSelector:@selector(stackedView:willRemoveViewController:)];
delegateFlags_.delegateDidRemoveViewController = [delegate respondsToSelector:@selector(stackedView:didRemoveViewController:)];
delegateFlags_.delegateDidStartDragging = [delegate respondsToSelector:@selector(stackedViewDidStartDragging:)];
delegateFlags_.delegateDidStopDragging = [delegate respondsToSelector:@selector(stackedViewDidStopDragging:)];
delegateFlags_.delegateWillPopViewControllers = [delegate respondsToSelector:@selector(stackedView:WillPopViewControllers:)];
delegateFlags_.delegateWillNotPopViewControllers = [delegate respondsToSelector:@selector(stackedView:WillNotPopViewControllers:)];
}
}

Expand Down Expand Up @@ -775,6 +791,9 @@ - (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer {

// set up designated drag destination
if (state == UIGestureRecognizerStateBegan) {
if (delegateFlags_.delegateDidStartDragging) {
[delegate_ stackedViewDidStartDragging:self];
}
if (offset > 0) {
lastDragOption_ = SVSnapOptionRight;
}else {
Expand All @@ -792,6 +811,44 @@ - (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer {
lastDragOffset_ = translatedPoint.x;
}

if(self.enablePopOffOnDragRight && [viewControllers_ count] > 0) {
UIViewController* fvc = (UIViewController*)[viewControllers_ objectAtIndex:0];
NSInteger currentDragDistance = (fvc.containerView.left - largeLeftInset_);

if(currentDragDistance > popOffDragDistance_ && lastDragOption_ != SVSnapOptionPopRight) {
lastDragOption_ = SVSnapOptionPopRight;
if(delegateFlags_.delegateWillPopViewControllers) {
NSArray* toPop;
if(self.popOffType == SVPopOptionAll) {
toPop = [self.viewControllers copy];
}
else if(self.popOffType == SVPopOptionAllButFirst) {
toPop = [self.viewControllers subarrayWithRange:NSMakeRange(1, [self.viewControllers count] - 1)];
}
else if(self.popOffType == SVPopOptionTop) {
toPop = [self.viewControllers subarrayWithRange:NSMakeRange([self.viewControllers count] - 1, 1)];
}
[delegate_ stackedView:self WillPopViewControllers:toPop];
}
}
else if(currentDragDistance < popOffDragDistance_ && lastDragOption_ == SVSnapOptionPopRight) {
lastDragOption_ = SVSnapOptionNearest;
if(delegateFlags_.delegateWillNotPopViewControllers) {
NSArray* toPop;
if(self.popOffType == SVPopOptionAll) {
toPop = [self.viewControllers copy];
}
else if(self.popOffType == SVPopOptionAllButFirst) {
toPop = [self.viewControllers subarrayWithRange:NSMakeRange(1, [self.viewControllers count] - 1)];
}
else if(self.popOffType == SVPopOptionTop) {
toPop = [self.viewControllers subarrayWithRange:NSMakeRange([self.viewControllers count] - 1, 1)];
}
[delegate_ stackedView:self WillNotPopViewControllers:toPop];
}
}
}

// perform snapping after gesture ended
BOOL gestureEnded = state == UIGestureRecognizerStateEnded;
if (gestureEnded) {
Expand All @@ -800,11 +857,30 @@ - (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer {
self.floatIndex = [self nearestValidFloatIndex:self.floatIndex round:PSSVRoundDown];
}else if(lastDragOption_ == SVSnapOptionLeft) {
self.floatIndex = [self nearestValidFloatIndex:self.floatIndex round:PSSVRoundUp];
}else {
}else if(lastDragOption_ == SVSnapOptionPopRight) {
self.floatIndex = 0.0;
if(self.popOffType == SVPopOptionAll) {
[self popToRootViewControllerAnimated:YES];
}
else if(self.popOffType == SVPopOptionAllButFirst) {
[self popToViewController:[self.viewControllers objectAtIndex:0] animated:YES];
}
else if(self.popOffType == SVPopOptionTop) {
if([self.viewControllers count] == 1)
[self popToRootViewControllerAnimated:YES];
else
[self popToViewController:[self.viewControllers objectAtIndex:[self.viewControllers count]-2] animated:YES];
}
}
else {
self.floatIndex = [self nearestValidFloatIndex:self.floatIndex round:PSSVRoundNearest];
}

[self alignStackAnimated:YES];

if(delegateFlags_.delegateDidStopDragging) {
[delegate_ stackedViewDidStopDragging:self];
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions PSStackedView/PSStackedViewDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,16 @@
/// viewController has been removed
- (void)stackedView:(PSStackedViewController *)stackedView didRemoveViewController:(UIViewController *)viewController;

/// stackcontroller will pop off view controllers because of drag to right
- (void)stackedView:(PSStackedViewController*)stackedView WillPopViewControllers:(NSArray*)controllers;

/// stackcontroller will no longer pop off view controllers because of drag to right
- (void)stackedView:(PSStackedViewController *)stackedView WillNotPopViewControllers:(NSArray*)controllers;

/// stackcontroller did start dragging stack
- (void)stackedViewDidStartDragging:(PSStackedViewController*)stackedView;

/// stackcontroller did stop dragging stack
- (void)stackedViewDidStopDragging:(PSStackedViewController*)stackedView;

@end
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ window.rootViewController = self.stackController;

PSStackedViewRootController's rootViewController is in the background and its left part is always visible. Adjust the size with leftInset and largeLeftInset.

PS: Added "Remove top view controller if user slides stack to the right"

Code by: [mball-crrc](https://github.com/mball-crrc/PSStackedView/tree/feature/pop_off_on_drag_right)

Pull merge by: [fabiosoft](https://github.com/fabiosoft) - [website](http://www.fabiosoft.com)

## Roadmap
- Add (conditional) support for the new child view controller system in iOS5
- Appledoc
Expand Down