mirror of
https://github.com/zhigang1992/ECSlidingViewController.git
synced 2026-03-29 08:58:37 +08:00
New API with documentation
This commit is contained in:
@@ -17,8 +17,7 @@
|
||||
ECSlidingViewController *slidingViewController = (ECSlidingViewController *)self.window.rootViewController;
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
|
||||
|
||||
slidingViewController.underLeftViewController = [storyboard instantiateViewControllerWithIdentifier:@"Menu"];
|
||||
slidingViewController.topViewController = [storyboard instantiateViewControllerWithIdentifier:@"FirstTop"];
|
||||
slidingViewController.topViewController = [storyboard instantiateViewControllerWithIdentifier:@"FirstTop"];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "ECSlidingViewController.h"
|
||||
#import "MenuViewController.h"
|
||||
#import "UnderRightViewController.h"
|
||||
|
||||
@interface FirstTopViewController : UIViewController
|
||||
|
||||
|
||||
@@ -8,20 +8,7 @@
|
||||
|
||||
#import "FirstTopViewController.h"
|
||||
|
||||
@interface FirstTopViewController()
|
||||
@property (nonatomic, unsafe_unretained) CGFloat peekRight;
|
||||
@property (nonatomic, unsafe_unretained) CGFloat peekLeft;
|
||||
@end
|
||||
|
||||
@implementation FirstTopViewController
|
||||
@synthesize peekRight;
|
||||
@synthesize peekLeft;
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
self.peekRight = 40.0f;
|
||||
self.peekLeft = 40.0f;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
@@ -34,24 +21,17 @@
|
||||
self.view.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.layer.bounds].CGPath;
|
||||
self.view.clipsToBounds = NO;
|
||||
|
||||
[self.slidingViewController enablePanningInDirection:ECSlideLeft forView:self.view peekAmount:self.peekLeft];
|
||||
[self.slidingViewController enablePanningInDirection:ECSlideRight forView:self.view peekAmount:self.peekRight];
|
||||
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
|
||||
self.slidingViewController.underRightViewController = [storyboard instantiateViewControllerWithIdentifier:@"UnderRight"];
|
||||
}
|
||||
|
||||
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
|
||||
{
|
||||
if ([self.slidingViewController underLeftShowing] && ![self.slidingViewController topViewIsOffScreen]) {
|
||||
[self.slidingViewController jumpToPeekAmount:self.peekRight inDirection:ECSlideRight];
|
||||
} else if ([self.slidingViewController underRightShowing] && ![self.slidingViewController topViewIsOffScreen]) {
|
||||
[self.slidingViewController jumpToPeekAmount:self.peekLeft inDirection:ECSlideLeft];
|
||||
} else if ([self.slidingViewController underLeftShowing] && [self.slidingViewController topViewIsOffScreen]) {
|
||||
[self.slidingViewController jumpToPeekAmount:0 inDirection:ECSlideRight];
|
||||
} else if ([self.slidingViewController underRightShowing] && [self.slidingViewController topViewIsOffScreen]) {
|
||||
[self.slidingViewController jumpToPeekAmount:0 inDirection:ECSlideLeft];
|
||||
|
||||
if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
|
||||
self.slidingViewController.underLeftViewController = [storyboard instantiateViewControllerWithIdentifier:@"Menu"];
|
||||
}
|
||||
|
||||
if (![self.slidingViewController.underRightViewController isKindOfClass:[UnderRightViewController class]]) {
|
||||
self.slidingViewController.underRightViewController = [storyboard instantiateViewControllerWithIdentifier:@"UnderRight"];
|
||||
}
|
||||
|
||||
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
|
||||
}
|
||||
|
||||
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
|
||||
@@ -68,12 +48,12 @@
|
||||
|
||||
- (IBAction)revealMenu:(id)sender
|
||||
{
|
||||
[self.slidingViewController slideInDirection:ECSlideRight peekAmount:self.peekRight onComplete:nil];
|
||||
[self.slidingViewController anchorTopViewTo:ECRight animations:nil onComplete:nil];
|
||||
}
|
||||
|
||||
- (IBAction)revealUnderRight:(id)sender
|
||||
{
|
||||
[self.slidingViewController slideInDirection:ECSlideLeft peekAmount:self.peekLeft onComplete:nil];
|
||||
[self.slidingViewController anchorTopViewTo:ECLeft animations:nil onComplete:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -20,6 +20,13 @@
|
||||
self.menuItems = [NSArray arrayWithObjects:@"First", @"Second", @"Third", nil];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[self.slidingViewController setAnchorRightPeekAmount:40.0f];
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)sectionIndex
|
||||
{
|
||||
return self.menuItems.count;
|
||||
@@ -43,11 +50,12 @@
|
||||
NSString *identifier = [NSString stringWithFormat:@"%@Top", [self.menuItems objectAtIndex:indexPath.row]];
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
|
||||
UIViewController *newTopViewController = [storyboard instantiateViewControllerWithIdentifier:identifier];
|
||||
[self.slidingViewController slideInDirection:ECSlideRight peekAmount:0.0f onComplete:^{
|
||||
|
||||
[self.slidingViewController anchorTopViewOffScreenTo:ECRight animations:nil onComplete:^{
|
||||
CGRect frame = self.slidingViewController.topViewController.view.frame;
|
||||
self.slidingViewController.topViewController = newTopViewController;
|
||||
self.slidingViewController.topViewController.view.frame = frame;
|
||||
[self.slidingViewController reset];
|
||||
[self.slidingViewController resetTopView];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "ECSlidingViewController.h"
|
||||
#import "MenuViewController.h"
|
||||
|
||||
@interface SecondTopViewController : UIViewController
|
||||
- (IBAction)revealMenu:(id)sender;
|
||||
|
||||
@@ -13,12 +13,21 @@
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
[self.slidingViewController enablePanningInDirection:ECSlideRight forView:self.view peekAmount:40.0f];
|
||||
|
||||
if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
|
||||
self.slidingViewController.underLeftViewController = [storyboard instantiateViewControllerWithIdentifier:@"Menu"];
|
||||
}
|
||||
self.slidingViewController.underRightViewController = nil;
|
||||
self.slidingViewController.anchorLeftPeekAmount = NSNotFound;
|
||||
self.slidingViewController.anchorLeftRevealAmount = NSNotFound;
|
||||
|
||||
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
|
||||
}
|
||||
|
||||
- (IBAction)revealMenu:(id)sender
|
||||
{
|
||||
[self.slidingViewController slideInDirection:ECSlideRight peekAmount:40.0f onComplete:nil];
|
||||
[self.slidingViewController anchorTopViewTo:ECRight animations:nil onComplete:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "ECSlidingViewController.h"
|
||||
#import "MenuViewController.h"
|
||||
#import "UnderRightViewController.h"
|
||||
|
||||
@interface ThirdTopViewController : UIViewController
|
||||
- (IBAction)revealMenu:(id)sender;
|
||||
|
||||
@@ -13,14 +13,23 @@
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
[self.slidingViewController enablePanningInDirection:ECSlideLeft forView:self.view peekAmount:40.0f];
|
||||
[self.slidingViewController enablePanningInDirection:ECSlideRight forView:self.view peekAmount:40.0f];
|
||||
self.slidingViewController.underRightViewController = nil;
|
||||
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
|
||||
|
||||
if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
|
||||
self.slidingViewController.underLeftViewController = [storyboard instantiateViewControllerWithIdentifier:@"Menu"];
|
||||
}
|
||||
|
||||
if (![self.slidingViewController.underRightViewController isKindOfClass:[UnderRightViewController class]]) {
|
||||
self.slidingViewController.underRightViewController = [storyboard instantiateViewControllerWithIdentifier:@"UnderRight"];
|
||||
}
|
||||
|
||||
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
|
||||
}
|
||||
|
||||
- (IBAction)revealMenu:(id)sender
|
||||
{
|
||||
[self.slidingViewController slideInDirection:ECSlideRight peekAmount:40.0f onComplete:nil];
|
||||
[self.slidingViewController anchorTopViewTo:ECRight animations:nil onComplete:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -9,19 +9,21 @@
|
||||
#import "UnderRightViewController.h"
|
||||
|
||||
@interface UnderRightViewController()
|
||||
@property (nonatomic, unsafe_unretained) CGFloat peekAmount;
|
||||
@property (nonatomic, unsafe_unretained) CGFloat peekLeftAmount;
|
||||
@property (nonatomic, unsafe_unretained) BOOL isSearching;
|
||||
- (void)updateLayoutForOrientation:(UIInterfaceOrientation)orientation;
|
||||
@end
|
||||
|
||||
@implementation UnderRightViewController
|
||||
@synthesize peekAmount;
|
||||
@synthesize peekLeftAmount;
|
||||
@synthesize isSearching;
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
self.peekAmount = 40.0f;
|
||||
[super viewDidLoad];
|
||||
self.peekLeftAmount = 40.0f;
|
||||
self.isSearching = NO;
|
||||
[self.slidingViewController setAnchorLeftPeekAmount:self.peekLeftAmount];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
@@ -50,8 +52,8 @@
|
||||
if (self.isSearching) {
|
||||
newLeftEdge = 0;
|
||||
} else {
|
||||
newLeftEdge = self.peekAmount;
|
||||
newWidth -= self.peekAmount;
|
||||
newLeftEdge = self.peekLeftAmount;
|
||||
newWidth -= self.peekLeftAmount;
|
||||
}
|
||||
|
||||
frame.origin.x = newLeftEdge;
|
||||
@@ -62,7 +64,7 @@
|
||||
|
||||
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
|
||||
{
|
||||
[UIView animateWithDuration:0.25f animations:^{
|
||||
[self.slidingViewController anchorTopViewOffScreenTo:ECLeft animations:^{
|
||||
CGRect frame = self.view.frame;
|
||||
frame.origin.x = 0.0f;
|
||||
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
|
||||
@@ -71,25 +73,25 @@
|
||||
frame.size.width = [UIScreen mainScreen].bounds.size.width;
|
||||
}
|
||||
self.view.frame = frame;
|
||||
} onComplete:^{
|
||||
self.isSearching = YES;
|
||||
}];
|
||||
[self.slidingViewController slideInDirection:ECSlideLeft peekAmount:-1.0f onComplete:nil];
|
||||
self.isSearching = YES;
|
||||
}
|
||||
|
||||
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
|
||||
{
|
||||
[UIView animateWithDuration:0.25f animations:^{
|
||||
[self.slidingViewController anchorTopViewTo:ECLeft animations:^{
|
||||
CGRect frame = self.view.frame;
|
||||
frame.origin.x = self.peekAmount;
|
||||
frame.origin.x = self.peekLeftAmount;
|
||||
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
|
||||
frame.size.width = [UIScreen mainScreen].bounds.size.height - self.peekAmount;
|
||||
frame.size.width = [UIScreen mainScreen].bounds.size.height - self.peekLeftAmount;
|
||||
} else if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
|
||||
frame.size.width = [UIScreen mainScreen].bounds.size.width - self.peekAmount;
|
||||
frame.size.width = [UIScreen mainScreen].bounds.size.width - self.peekLeftAmount;
|
||||
}
|
||||
self.view.frame = frame;
|
||||
} onComplete:^{
|
||||
self.isSearching = NO;
|
||||
}];
|
||||
[self.slidingViewController slideInDirection:ECSlideLeft peekAmount:self.peekAmount onComplete:nil];
|
||||
self.isSearching = NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -9,27 +9,122 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "UIImage+UIImage_ImageWithUIView.h"
|
||||
|
||||
/** @constant ECSide side of screen */
|
||||
typedef enum {
|
||||
ECSlideLeft,
|
||||
ECSlideRight
|
||||
} ECSlideDirection;
|
||||
/** Left side of screen */
|
||||
ECLeft,
|
||||
/** Right side of screen */
|
||||
ECRight
|
||||
} ECSide;
|
||||
|
||||
/** @constant ECResetStrategy top view behavior while anchored. */
|
||||
typedef enum {
|
||||
/** No reset strategy will be used */
|
||||
ECNone = 0,
|
||||
/** Tapping the top view will reset it */
|
||||
ECTapping = 1 << 0,
|
||||
/** Panning will be enabled on the top view. If it is panned and released towards the reset position it will reset, otherwise it will slide towards the anchored position. */
|
||||
ECPanning = 1 << 1
|
||||
} ECResetStrategy;
|
||||
|
||||
/** ECSlidingViewController is a view controller container that presents its child view controllers in two layers. The top layer can be panned to reveal the layers below it. */
|
||||
@interface ECSlidingViewController : UIViewController
|
||||
|
||||
/** Returns the view controller that will be visible when the top view is slide to the right.
|
||||
|
||||
This view controller is typically a menu or top-level view that switches out the top view controller.
|
||||
*/
|
||||
@property (nonatomic, strong) UIViewController *underLeftViewController;
|
||||
|
||||
/** Returns the view controller that will be visible when the top view is slide to the left.
|
||||
|
||||
This view controller is typically a supplemental view to the top view.
|
||||
*/
|
||||
@property (nonatomic, strong) UIViewController *underRightViewController;
|
||||
|
||||
/** Returns the top view controller.
|
||||
|
||||
This is the main view controller that is presented above the other view controllers.
|
||||
*/
|
||||
@property (nonatomic, strong) UIViewController *topViewController;
|
||||
|
||||
- (void)slideInDirection:(ECSlideDirection)slideDirection peekAmount:(CGFloat)peekAmount onComplete:(void(^)())completeBlock;
|
||||
- (void)enablePanningInDirection:(ECSlideDirection)slideDirection forView:(UIView *)view peekAmount:(CGFloat)peekAmount;
|
||||
- (void)jumpToPeekAmount:(CGFloat)peekAmount inDirection:(ECSlideDirection)direction;
|
||||
- (void)reset;
|
||||
- (BOOL)underLeftShowing;
|
||||
- (BOOL)underRightShowing;
|
||||
- (BOOL)topViewIsOffScreen;
|
||||
/** Returns the number of points the top view is visible when the top view is anchored to the left side.
|
||||
|
||||
This value is fixed after rotation. If the number of points to reveal needs to be fixed, use anchorLeftRevealAmount.
|
||||
|
||||
@see anchorLeftRevealAmount
|
||||
*/
|
||||
@property (nonatomic, unsafe_unretained) CGFloat anchorLeftPeekAmount;
|
||||
|
||||
/** Returns the number of points the top view is visible when the top view is anchored to the right side.
|
||||
|
||||
This value is fixed after rotation. If the number of points to reveal needs to be fixed, use anchorRightRevealAmount.
|
||||
|
||||
@see anchorRightRevealAmount
|
||||
*/
|
||||
@property (nonatomic, unsafe_unretained) CGFloat anchorRightPeekAmount;
|
||||
|
||||
/** Returns the number of points the under right view is visible when the top view is anchored to the left side.
|
||||
|
||||
This value is fixed after rotation. If the number of points to peek needs to be fixed, use anchorLeftPeekAmount.
|
||||
|
||||
@see anchorLeftPeekAmount
|
||||
*/
|
||||
@property (nonatomic, unsafe_unretained) CGFloat anchorLeftRevealAmount;
|
||||
|
||||
/** Returns the number of points the under left view is visible when the top view is anchored to the right side.
|
||||
|
||||
This value is fixed after rotation. If the number of points to peek needs to be fixed, use anchorRightPeekAmount.
|
||||
|
||||
@see anchorRightPeekAmount
|
||||
*/
|
||||
@property (nonatomic, unsafe_unretained) CGFloat anchorRightRevealAmount;
|
||||
|
||||
/** Specifies if the user should be able to interact with the top view when it is anchored.
|
||||
|
||||
By default, this is set to NO
|
||||
*/
|
||||
@property (nonatomic, unsafe_unretained) BOOL shouldAllowUserInteractionsWhenAnchored;
|
||||
|
||||
/** Returns the strategy for resetting the top view when it is anchored.
|
||||
|
||||
By default, this is set to ECPanning | ECTapping to allow both panning and tapping to reset the top view.
|
||||
|
||||
If this is set to ECNone, then there must be a custom way to reset the top view otherwise it will stay anchored.
|
||||
*/
|
||||
@property (nonatomic, unsafe_unretained) ECResetStrategy resetStrategy;
|
||||
|
||||
/** Returns a horizontal panning gesture for moving the top view.
|
||||
|
||||
This is typically added to the top view or a top view's navigation bar.
|
||||
*/
|
||||
- (UIPanGestureRecognizer *)panGesture;
|
||||
|
||||
/** Slides the top view in the direction of the specified side.
|
||||
|
||||
A peek amount or reveal amount must be set for the given side. The top view will anchor to one of those specified values.
|
||||
|
||||
@param side The side for the top view to slide towards.
|
||||
@param animations Perform changes to properties that will be animated while top view is moved off screen. Can be nil.
|
||||
@param onComplete Executed after the animation is completed. Can be nil.
|
||||
*/
|
||||
- (void)anchorTopViewTo:(ECSide)side animations:(void(^)())animations onComplete:(void(^)())complete;
|
||||
|
||||
/** Slides the top view off of the screen in the direction of the specified side.
|
||||
|
||||
@param side The side for the top view to slide off the screen towards.
|
||||
@param animations Perform changes to properties that will be animated while top view is moved off screen. Can be nil.
|
||||
@param onComplete Executed after the animation is completed. Can be nil.
|
||||
*/
|
||||
- (void)anchorTopViewOffScreenTo:(ECSide)side animations:(void(^)())animations onComplete:(void(^)())complete;
|
||||
|
||||
/** Slides the top view back to the center. */
|
||||
- (void)resetTopView;
|
||||
|
||||
@end
|
||||
|
||||
/** UIViewController extension */
|
||||
@interface UIViewController(SlidingViewExtension)
|
||||
/** Convience method for getting access to the ECSlidingViewController instance */
|
||||
- (ECSlidingViewController *)slidingViewController;
|
||||
@end
|
||||
@@ -10,14 +10,16 @@
|
||||
|
||||
@interface ECSlidingViewController()
|
||||
|
||||
@property (nonatomic, unsafe_unretained) CGFloat rightSidePeekAmount;
|
||||
@property (nonatomic, unsafe_unretained) CGFloat leftSidePeekAmount;
|
||||
@property (nonatomic, strong) UIButton *topViewSnapshot;
|
||||
@property (nonatomic, unsafe_unretained) CGFloat initialTouchPositionX;
|
||||
@property (nonatomic, unsafe_unretained) CGFloat initialHoizontalCenter;
|
||||
@property (nonatomic, strong) UIPanGestureRecognizer *panGesture;
|
||||
@property (nonatomic, strong) UITapGestureRecognizer *resetTapGesture;
|
||||
|
||||
- (BOOL)underLeftShowing;
|
||||
- (BOOL)underRightShowing;
|
||||
- (BOOL)topViewIsOffScreen;
|
||||
|
||||
- (NSUInteger)autoResizeToFillScreen;
|
||||
- (UIView *)topView;
|
||||
- (UIView *)underLeftView;
|
||||
@@ -57,32 +59,34 @@
|
||||
@synthesize underLeftViewController = _underLeftViewController;
|
||||
@synthesize underRightViewController = _underRightViewController;
|
||||
@synthesize topViewController = _topViewController;
|
||||
@synthesize anchorLeftPeekAmount;
|
||||
@synthesize anchorRightPeekAmount;
|
||||
@synthesize anchorLeftRevealAmount;
|
||||
@synthesize anchorRightRevealAmount;
|
||||
@synthesize shouldAllowUserInteractionsWhenAnchored;
|
||||
@synthesize resetStrategy;
|
||||
|
||||
// category properties
|
||||
@synthesize leftSidePeekAmount;
|
||||
@synthesize rightSidePeekAmount;
|
||||
@synthesize topViewSnapshot;
|
||||
@synthesize initialTouchPositionX;
|
||||
@synthesize initialHoizontalCenter;
|
||||
@synthesize panGesture;
|
||||
@synthesize panGesture = _panGesture;
|
||||
@synthesize resetTapGesture;
|
||||
|
||||
- (void)setTopViewController:(UIViewController *)theTopViewController
|
||||
{
|
||||
self.leftSidePeekAmount = NSNotFound;
|
||||
self.rightSidePeekAmount = NSNotFound;
|
||||
|
||||
[self removeTopViewSnapshot];
|
||||
[_topViewController.view removeFromSuperview];
|
||||
[_topViewController removeFromParentViewController];
|
||||
|
||||
_topViewController = theTopViewController;
|
||||
[_topViewController.view setAutoresizingMask:self.autoResizeToFillScreen];
|
||||
[_topViewController.view setFrame:self.view.bounds];
|
||||
|
||||
[self addChildViewController:self.topViewController];
|
||||
[self.topViewController didMoveToParentViewController:self];
|
||||
|
||||
[_topViewController.view setAutoresizingMask:self.autoResizeToFillScreen];
|
||||
[_topViewController.view setFrame:self.view.bounds];
|
||||
|
||||
[self.view addSubview:_topViewController.view];
|
||||
}
|
||||
|
||||
@@ -94,12 +98,12 @@
|
||||
_underLeftViewController = theUnderLeftViewController;
|
||||
|
||||
if (_underLeftViewController) {
|
||||
[_underLeftViewController.view setAutoresizingMask:self.autoResizeToFillScreen];
|
||||
[_underLeftViewController.view setFrame:self.view.bounds];
|
||||
|
||||
[self addChildViewController:self.underLeftViewController];
|
||||
[self.underLeftViewController didMoveToParentViewController:self];
|
||||
|
||||
[_underLeftViewController.view setAutoresizingMask:self.autoResizeToFillScreen];
|
||||
[_underLeftViewController.view setFrame:self.view.bounds];
|
||||
|
||||
[self.view insertSubview:_underLeftViewController.view atIndex:0];
|
||||
}
|
||||
}
|
||||
@@ -112,20 +116,33 @@
|
||||
_underRightViewController = theUnderRightViewController;
|
||||
|
||||
if (_underRightViewController) {
|
||||
[_underRightViewController.view setAutoresizingMask:self.autoResizeToFillScreen];
|
||||
[_underRightViewController.view setFrame:self.view.bounds];
|
||||
|
||||
[self addChildViewController:self.underRightViewController];
|
||||
[self.underRightViewController didMoveToParentViewController:self];
|
||||
|
||||
[_underRightViewController.view setAutoresizingMask:self.autoResizeToFillScreen];
|
||||
[_underRightViewController.view setFrame:self.view.bounds];
|
||||
|
||||
[self.view insertSubview:_underRightViewController.view atIndex:0];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
self.resetTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reset)];
|
||||
self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(updateTopViewHorizontalCenterWithRecognizer:)];
|
||||
self.resetTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(resetTopView)];
|
||||
_panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(updateTopViewHorizontalCenterWithRecognizer:)];
|
||||
}
|
||||
|
||||
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
|
||||
{
|
||||
if ([self underRightShowing] && ![self topViewIsOffScreen]) {
|
||||
[self updateTopViewHorizontalCenter:-self.resettedCenter + self.anchorLeftPeekAmount];
|
||||
} else if ([self underRightShowing] && [self topViewIsOffScreen]) {
|
||||
[self updateTopViewHorizontalCenter:-self.resettedCenter];
|
||||
} else if ([self underLeftShowing] && ![self topViewIsOffScreen]) {
|
||||
[self updateTopViewHorizontalCenter:self.screenWidth + self.resettedCenter - self.anchorRightPeekAmount];
|
||||
} else if ([self underLeftShowing] && [self topViewIsOffScreen]) {
|
||||
[self updateTopViewHorizontalCenter:self.screenWidth + self.resettedCenter];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateTopViewHorizontalCenterWithRecognizer:(UIPanGestureRecognizer *)recognizer
|
||||
@@ -140,7 +157,7 @@
|
||||
CGFloat panAmount = self.initialTouchPositionX - currentTouchPositionX;
|
||||
CGFloat newCenterPosition = self.initialHoizontalCenter - panAmount;
|
||||
|
||||
if ((newCenterPosition < self.resettedCenter && self.leftSidePeekAmount == NSNotFound) || (newCenterPosition > self.resettedCenter && self.rightSidePeekAmount == NSNotFound)) {
|
||||
if ((newCenterPosition < self.resettedCenter && self.anchorLeftPeekAmount == NSNotFound) || (newCenterPosition > self.resettedCenter && self.anchorRightPeekAmount == NSNotFound)) {
|
||||
newCenterPosition = self.resettedCenter;
|
||||
}
|
||||
|
||||
@@ -152,63 +169,69 @@
|
||||
CGFloat currentVelocityX = currentVelocityPoint.x;
|
||||
|
||||
if ([self underLeftShowing] && currentVelocityX > 100) {
|
||||
[self slideInDirection:ECSlideRight peekAmount:self.rightSidePeekAmount onComplete:nil];
|
||||
[self anchorTopViewTo:ECRight animations:nil onComplete:nil];
|
||||
} else if ([self underRightShowing] && currentVelocityX < 100) {
|
||||
[self slideInDirection:ECSlideLeft peekAmount:self.leftSidePeekAmount onComplete:nil];
|
||||
[self anchorTopViewTo:ECLeft animations:nil onComplete:nil];
|
||||
} else {
|
||||
[self reset];
|
||||
[self resetTopView];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)slideInDirection:(ECSlideDirection)slideDirection peekAmount:(CGFloat)peekAmount onComplete:(void(^)())completeBlock;
|
||||
- (UIPanGestureRecognizer *)panGesture
|
||||
{
|
||||
return _panGesture;
|
||||
}
|
||||
|
||||
- (void)anchorTopViewTo:(ECSide)side animations:(void (^)())animations onComplete:(void (^)())complete
|
||||
{
|
||||
CGFloat newCenter = self.topView.center.x;
|
||||
|
||||
if (slideDirection == ECSlideLeft) {
|
||||
newCenter = -self.screenWidth + self.resettedCenter + peekAmount;
|
||||
} else if (slideDirection == ECSlideRight) {
|
||||
newCenter = self.screenWidth + self.resettedCenter - peekAmount;
|
||||
if (side == ECLeft) {
|
||||
newCenter = -self.resettedCenter + self.anchorLeftPeekAmount;
|
||||
} else if (side == ECRight) {
|
||||
newCenter = self.screenWidth + self.resettedCenter - self.anchorRightPeekAmount;
|
||||
}
|
||||
|
||||
[self topViewHorizontalCenterWillChange:newCenter];
|
||||
|
||||
[UIView animateWithDuration:0.25f animations:^{
|
||||
[self jumpToPeekAmount:peekAmount inDirection:slideDirection];
|
||||
} completion:^(BOOL finished) {
|
||||
if (completeBlock) {
|
||||
completeBlock();
|
||||
if (animations) {
|
||||
animations();
|
||||
}
|
||||
[self updateTopViewHorizontalCenter:newCenter];
|
||||
} completion:^(BOOL finished){
|
||||
if (complete) {
|
||||
complete();
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)enablePanningInDirection:(ECSlideDirection)slideDirection forView:(UIView *)view peekAmount:(CGFloat)peekAmount
|
||||
{
|
||||
if (slideDirection == ECSlideLeft) {
|
||||
self.leftSidePeekAmount = peekAmount;
|
||||
} else if (slideDirection == ECSlideRight) {
|
||||
self.rightSidePeekAmount = peekAmount;
|
||||
}
|
||||
|
||||
if (![[view gestureRecognizers] containsObject:self.panGesture]) {
|
||||
[view addGestureRecognizer:self.panGesture];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)jumpToPeekAmount:(CGFloat)peekAmount inDirection:(ECSlideDirection)slideDirection
|
||||
- (void)anchorTopViewOffScreenTo:(ECSide)side animations:(void(^)())animations onComplete:(void(^)())complete
|
||||
{
|
||||
CGFloat newCenter = self.topView.center.x;
|
||||
|
||||
if (slideDirection == ECSlideLeft) {
|
||||
newCenter = -self.screenWidth + self.resettedCenter + peekAmount;
|
||||
} else if (slideDirection == ECSlideRight) {
|
||||
newCenter = self.screenWidth + self.resettedCenter - peekAmount;
|
||||
if (side == ECLeft) {
|
||||
newCenter = -self.resettedCenter;
|
||||
} else if (side == ECRight) {
|
||||
newCenter = self.screenWidth + self.resettedCenter;
|
||||
}
|
||||
|
||||
[self updateTopViewHorizontalCenter:newCenter];
|
||||
[self topViewHorizontalCenterWillChange:newCenter];
|
||||
|
||||
[UIView animateWithDuration:0.25f animations:^{
|
||||
if (animations) {
|
||||
animations();
|
||||
}
|
||||
[self updateTopViewHorizontalCenter:newCenter];
|
||||
} completion:^(BOOL finished){
|
||||
if (complete) {
|
||||
complete();
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
- (void)resetTopView
|
||||
{
|
||||
[UIView animateWithDuration:0.25f animations:^{
|
||||
[self updateTopViewHorizontalCenter:self.resettedCenter];
|
||||
@@ -229,7 +252,7 @@
|
||||
|
||||
- (BOOL)topViewIsOffScreen
|
||||
{
|
||||
return self.topView.center.x <= -self.resettedCenter || self.topView.center.x >= self.screenWidth + self.resettedCenter;
|
||||
return self.topView.center.x <= -self.resettedCenter + 1 || self.topView.center.x >= self.screenWidth + self.resettedCenter - 1;
|
||||
}
|
||||
|
||||
- (NSUInteger)autoResizeToFillScreen
|
||||
|
||||
Reference in New Issue
Block a user