Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added previewBounce methods and delegate calls. Also added necessary …

…QuartzCore framework to project.
  • Loading branch information...
commit b7064088e70c6ac296d27ba7ca588606498d9140 1 parent 2c7cbce
@cbpowell cbpowell authored
View
9 ViewDeck/IIViewDeckController.h
@@ -230,6 +230,11 @@ typedef void (^IIViewDeckControllerBounceBlock) (IIViewDeckController *controlle
- (BOOL)closeOpenViewBouncing:(IIViewDeckControllerBounceBlock)bounced;
- (BOOL)closeOpenViewBouncing:(IIViewDeckControllerBounceBlock)bounced completion:(IIViewDeckControllerBlock)completed;
+- (BOOL)previewBounceView:(IIViewDeckSide)viewDeckSide;
+- (BOOL)previewBounceView:(IIViewDeckSide)viewDeckSide withCompletion:(IIViewDeckControllerBlock)completed;
+- (BOOL)previewBounceView:(IIViewDeckSide)viewDeckSide toDistance:(CGFloat)distance duration:(NSTimeInterval)duration callDelegate:(BOOL)callDelegate completion:(IIViewDeckControllerBlock)completed;
+- (BOOL)previewBounceView:(IIViewDeckSide)viewDeckSide toDistance:(CGFloat)distance duration:(NSTimeInterval)duration numberOfBounces:(CGFloat)numberOfBounces dampingFactor:(CGFloat)zeta callDelegate:(BOOL)callDelegate completion:(IIViewDeckControllerBlock)completed;
+
- (BOOL)canRightViewPushViewControllerOverCenterController;
- (void)rightViewPushViewControllerOverCenterController:(UIViewController*)controller;
@@ -265,6 +270,10 @@ typedef void (^IIViewDeckControllerBounceBlock) (IIViewDeckController *controlle
- (void)viewDeckController:(IIViewDeckController*)viewDeckController didCloseViewSide:(IIViewDeckSide)viewDeckSide animated:(BOOL)animated;
- (void)viewDeckController:(IIViewDeckController*)viewDeckController didShowCenterViewFromSide:(IIViewDeckSide)viewDeckSide animated:(BOOL)animated;
+- (BOOL)viewDeckController:(IIViewDeckController *)viewDeckController shouldPreviewBounceViewSide:(IIViewDeckSide)viewDeckSide;
+- (void)viewDeckController:(IIViewDeckController *)viewDeckController willPreviewBounceViewSide:(IIViewDeckSide)viewDeckSide animated:(BOOL)animated;
+- (void)viewDeckController:(IIViewDeckController *)viewDeckController didPreviewBounceViewSide:(IIViewDeckSide)viewDeckSide animated:(BOOL)animated;
+
@end
View
131 ViewDeck/IIViewDeckController.m
@@ -178,6 +178,8 @@ - (void)restoreShadowToSlidingView;
- (void)arrangeViewsAfterRotation;
- (CGFloat)relativeStatusBarHeight;
+- (NSArray *)bouncingValuesForViewSide:(IIViewDeckSide)viewSide maximumBounce:(CGFloat)maxBounce numberOfBounces:(CGFloat)numberOfBounces dampingFactor:(CGFloat)zeta duration:(NSTimeInterval)duration;
+
- (void)centerViewVisible;
- (void)centerViewHidden;
- (void)centerTapped;
@@ -1696,6 +1698,135 @@ - (BOOL)closeBottomViewBouncing:(IIViewDeckControllerBounceBlock)bounced complet
return [self closeSideView:IIViewDeckBottomSide bounceOffset:-self.referenceBounds.size.height bounced:bounced completion:completed];
}
+#pragma mark - Side Bouncing
+
+- (BOOL)previewBounceView:(IIViewDeckSide)viewDeckSide {
+ return [self previewBounceView:viewDeckSide withCompletion:nil];
+}
+
+- (BOOL)previewBounceView:(IIViewDeckSide)viewDeckSide withCompletion:(IIViewDeckControllerBlock)completed {
+ return [self previewBounceView:viewDeckSide toDistance:40.0f duration:1.2f callDelegate:YES completion:completed];
+}
+
+- (BOOL)previewBounceView:(IIViewDeckSide)viewDeckSide toDistance:(CGFloat)distance duration:(NSTimeInterval)duration callDelegate:(BOOL)callDelegate completion:(IIViewDeckControllerBlock)completed {
+ return [self previewBounceView:viewDeckSide toDistance:distance duration:duration numberOfBounces:4.0f dampingFactor:0.40f callDelegate:callDelegate completion:completed];
+}
+
+- (BOOL)previewBounceView:(IIViewDeckSide)viewDeckSide toDistance:(CGFloat)distance duration:(NSTimeInterval)duration numberOfBounces:(CGFloat)numberOfBounces dampingFactor:(CGFloat)zeta callDelegate:(BOOL)callDelegate completion:(IIViewDeckControllerBlock)completed {
+ // Check if the requested side to bounce is nil, or if it's already open
+ if (![self controllerForSide:viewDeckSide] || [self isSideOpen:viewDeckSide]) return NO;
+
+ // check the delegate to allow bouncing
+ if (callDelegate && ![self checkDelegate:@selector(viewDeckController:shouldPreviewBounceViewSide:) side:viewDeckSide]) return NO;
+ // also close any view that's open. Since the delegate can cancel the close, check the result.
+ if (callDelegate && [self isAnySideOpen]) {
+ if (![self toggleOpenViewAnimated:YES]) return NO;
+ }
+ // check for in-flight preview bounce animation, do not add another if so
+ if ([self.slidingControllerView.layer animationForKey:@"previewBounceAnimation"]) {
+ return NO;
+ }
+
+ NSArray *animationValues = [self bouncingValuesForViewSide:viewDeckSide maximumBounce:distance numberOfBounces:numberOfBounces dampingFactor:zeta duration:duration];
+ if (!animationValues) {
+ return NO;
+ }
+
+ UIViewController *previewController = [self controllerForSide:viewDeckSide];
+
+ CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position.x"];
+ animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
+ animation.duration = duration;
+ animation.values = animationValues;
+ animation.removedOnCompletion = YES;
+
+ previewController.view.hidden = NO;
+
+ [CATransaction begin];
+ [CATransaction setValue:[NSNumber numberWithFloat:duration] forKey:kCATransactionAnimationDuration];
+ [CATransaction setCompletionBlock:^{
+ // only re-hide controller if the view has not been panned mid-animation
+ if (_offset == 0.0f) {
+ previewController.view.hidden = YES;
+ }
+
+ // perform completion and delegate call
+ if (completed) completed(self, YES);
+ if (callDelegate) [self performDelegate:@selector(viewDeckController:didPreviewBounceViewSide:) side:viewDeckSide animated:YES];
+ }];
+ [self.slidingControllerView.layer addAnimation:animation forKey:@"previewBounceAnimation"];
+
+ // Inform delegate
+ if (callDelegate) [self performDelegate:@selector(viewDeckController:willPreviewBounceViewSide:animated:) side:viewDeckSide animated:YES];
+
+ // Commit animation
+ [CATransaction commit];
+
+ return YES;
+}
+
+- (NSArray *)bouncingValuesForViewSide:(IIViewDeckSide)viewDeckSide maximumBounce:(CGFloat)maxBounce numberOfBounces:(CGFloat)numberOfBounces dampingFactor:(CGFloat)zeta duration:(NSTimeInterval)duration {
+
+ // Underdamped, Free Vibration of a SDOF System
+ // u(t) = abs(e^(-zeta * wn * t) * ((Vo/wd) * sin(wd * t))
+
+ // Vo, initial velocity, is calculated to provide the desired maxBounce and
+ // animation duration. The damped period (wd) and distance of the maximum (first)
+ // bounce can be controlled either via the initial condition Vo or the damping
+ // factor zeta for a desired duration, Vo is simpler mathematically.
+
+ NSUInteger steps = (NSUInteger)MIN(floorf(duration * 100.0f), 100);
+ float time = 0.0;
+
+ NSMutableArray *values = [NSMutableArray arrayWithCapacity:steps];
+
+ double offset = 0.0;
+ float Td = (2.0f * duration) / numberOfBounces; //Damped period, calculated to give the number of bounces desired in the duration specified (2 bounces per Td)
+ float wd = (2.0f * M_PI)/Td; // Damped frequency
+ zeta = MIN(MAX(0.0001f, zeta), 0.9999f); // For an underdamped system, we must have 0 < zeta < 1
+ float zetaFactor = sqrtf(1 - powf(zeta, 2.0f)); // Used in multiple places
+ float wn = wd/zetaFactor; // Natural frequency
+ float Vo = maxBounce * wd/(expf(-zeta/zetaFactor * (0.18f * Td) * wd) * sinf(0.18f * Td * wd));
+
+ // Determine parameters based on direction
+ CGFloat position = 0.0f;
+ NSInteger direction = 1;
+ switch (viewDeckSide) {
+ case IIViewDeckLeftSide:
+ position = self.slidingControllerView.layer.position.x;
+ direction = 1;
+ break;
+
+ case IIViewDeckRightSide:
+ position = self.slidingControllerView.layer.position.x;
+ direction = -1;
+ break;
+
+ case IIViewDeckTopSide:
+ position = self.slidingControllerView.layer.position.y;
+ direction = 1;
+ break;
+
+ case IIViewDeckBottomSide:
+ position = self.slidingControllerView.layer.position.y;
+ direction = -1;
+ break;
+
+ default:
+ return nil;
+ break;
+ }
+
+ // Calculate steps
+ for (int t = 0; t < steps; t++) {
+ time = (t / (float)steps) * duration;
+ offset = abs(expf(-zeta * wn * time) * ((Vo / wd) * sin(wd * time)));
+ offset = direction * [self limitOffset:offset forOrientation:IIViewDeckOffsetOrientationFromIIViewDeckSide(viewDeckSide)] + position;
+ [values addObject:[NSNumber numberWithFloat:offset]];
+ }
+
+ return values;
+}
#pragma mark - toggling open view
View
4 ViewDeckExample.xcodeproj/project.pbxproj
@@ -26,6 +26,7 @@
E2955F9914B7D678003DDB4E /* NestViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E2955F9714B7D678003DDB4E /* NestViewController.xib */; };
E2B01A28155B385600E05FB9 /* PushedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E2B01A26155B385600E05FB9 /* PushedViewController.m */; };
E2B01A29155B385600E05FB9 /* PushedViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E2B01A27155B385600E05FB9 /* PushedViewController.xib */; };
+ EA82B9FE167CFB670028F389 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA82B9FD167CFB670028F389 /* QuartzCore.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -59,6 +60,7 @@
E2B01A25155B385600E05FB9 /* PushedViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PushedViewController.h; sourceTree = "<group>"; };
E2B01A26155B385600E05FB9 /* PushedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PushedViewController.m; sourceTree = "<group>"; };
E2B01A27155B385600E05FB9 /* PushedViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PushedViewController.xib; sourceTree = "<group>"; };
+ EA82B9FD167CFB670028F389 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -66,6 +68,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ EA82B9FE167CFB670028F389 /* QuartzCore.framework in Frameworks */,
E240A9AC148AB3770077282A /* UIKit.framework in Frameworks */,
E240A9AE148AB3770077282A /* Foundation.framework in Frameworks */,
E240A9B0148AB3770077282A /* CoreGraphics.framework in Frameworks */,
@@ -95,6 +98,7 @@
E240A9AA148AB3770077282A /* Frameworks */ = {
isa = PBXGroup;
children = (
+ EA82B9FD167CFB670028F389 /* QuartzCore.framework */,
E240A9AB148AB3770077282A /* UIKit.framework */,
E240A9AD148AB3770077282A /* Foundation.framework */,
E240A9AF148AB3770077282A /* CoreGraphics.framework */,

0 comments on commit b706408

Please sign in to comment.
Something went wrong with that request. Please try again.