From c00c16405293d6c8ee5260547e0cca0b07bc4c43 Mon Sep 17 00:00:00 2001 From: xhzengAIB Date: Sat, 5 Oct 2013 02:08:12 +0000 Subject: [PATCH 1/4] Add UIPangestureRecognizer to open and close Menu --- .../TWTSideMenuViewController.m | 104 +++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/TWTSideMenuViewController/TWTSideMenuViewController.m b/TWTSideMenuViewController/TWTSideMenuViewController.m index d526ec0..cb4b7ed 100644 --- a/TWTSideMenuViewController/TWTSideMenuViewController.m +++ b/TWTSideMenuViewController/TWTSideMenuViewController.m @@ -29,7 +29,12 @@ this software and associated documentation files (the "Software"), to deal in static NSTimeInterval const kDefaultSwapAnimationDuration = 0.45; static NSTimeInterval const kDefaultSwapAnimationClosedDuration = 0.35; -@interface TWTSideMenuViewController () +@interface TWTSideMenuViewController () { + CGAffineTransform leftCloseTransfrom; + CGAffineTransform mainOpenTransfrom; + + CGAffineTransform originScaleTransfrom; +} @property (nonatomic, strong) UIButton *closeOverlayButton; @property (nonatomic, strong) UIView *containerView; @@ -75,6 +80,9 @@ - (void)viewDidLoad { [super viewDidLoad]; + UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureHandle:)]; + [self.view addGestureRecognizer:panGesture]; + self.menuViewController.view.frame = self.view.bounds; [self.view addSubview:self.menuViewController.view]; @@ -86,6 +94,97 @@ - (void)viewDidLoad self.menuViewController.view.transform = [self closeTransformForMenuView]; } +#pragma mark - UIGesture + +- (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { + UIGestureRecognizerState state = panGesture.state; + + CGPoint translation = [panGesture translationInView:panGesture.view]; + + switch (state) { + case UIGestureRecognizerStateBegan: + case UIGestureRecognizerStateChanged: { + CGFloat xOffset = translation.x; + + float scaleOffset = (1.0 - ((xOffset) / self.view.bounds.size.width)); + + if (scaleOffset >= self.zoomScale && scaleOffset <= (2.0 - self.zoomScale)) { + if (self.isOpen) { + CGAffineTransform originTransfrom = originScaleTransfrom; + CGAffineTransform scaleTransform = CGAffineTransformScale(originTransfrom, scaleOffset, scaleOffset); + CGAffineTransform openTransfrom = CGAffineTransformTranslate(scaleTransform, xOffset, 0); + self.containerView.transform = openTransfrom; + + self.menuViewController.view.transform = CGAffineTransformTranslate(CGAffineTransformScale(CGAffineTransformIdentity, scaleOffset, scaleOffset), xOffset, 0); + } else { + + + + //main + CGAffineTransform mainPanTransform = CGAffineTransformScale(CGAffineTransformIdentity, scaleOffset, scaleOffset); + + // left + + CGAffineTransform leftPanTransform = CGAffineTransformScale(leftCloseTransfrom, scaleOffset, scaleOffset); + + CGAffineTransform translationTransfrom = CGAffineTransformTranslate(leftPanTransform, xOffset, 0); + self.menuViewController.view.transform = translationTransfrom; + + self.containerView.transform = CGAffineTransformTranslate(mainPanTransform, xOffset, 0); + } + } else if (xOffset < 300) { + + if (self.open) { + if (xOffset > -178) { + CGAffineTransform originTransfrom = originScaleTransfrom; + CGAffineTransform scaleTransform = CGAffineTransformScale(originTransfrom, scaleOffset, scaleOffset); + CGAffineTransform openTransfrom = CGAffineTransformTranslate(scaleTransform, xOffset, 0); + self.containerView.transform = openTransfrom; + } + } else { + + CGAffineTransform panTransform = CGAffineTransformScale(CGAffineTransformIdentity, self.zoomScale, self.zoomScale); + self.containerView.transform = CGAffineTransformTranslate(panTransform, xOffset, 0); + } + + } + + break; + } + case UIGestureRecognizerStateCancelled: + case UIGestureRecognizerStateEnded: { + if ([panGesture velocityInView:panGesture.view].x < 0) { + // 还原 + + [UIView animateWithDuration:0.5 animations:^{ + self.containerView.transform = CGAffineTransformIdentity; + self.menuViewController.view.transform = leftCloseTransfrom; + } completion:^(BOOL finished) { + self.open = !finished; + }]; + + } else { + + // 打开 + [UIView animateWithDuration:0.5 animations:^{ + CGAffineTransform scaleTranfrom = CGAffineTransformTranslate(CGAffineTransformIdentity, 178, 0); + CGAffineTransform openTransfrom = CGAffineTransformScale(scaleTranfrom, self.zoomScale, self.zoomScale); + originScaleTransfrom = openTransfrom; + self.containerView.transform = openTransfrom; + + self.menuViewController.view.transform = CGAffineTransformIdentity; + } completion:^(BOOL finished) { + self.open = finished; + }]; + + } + break; + } + default: + break; + } +} + #pragma mark - Status Bar management - (UIStatusBarStyle)preferredStatusBarStyle @@ -114,7 +213,8 @@ - (CGAffineTransform)closeTransformForMenuView { CGFloat transformSize = 1.0f + (1.0f * self.zoomScale); CGAffineTransform transform = CGAffineTransformScale(self.menuViewController.view.transform, transformSize, transformSize); - return CGAffineTransformTranslate(transform, -(CGRectGetMidX(self.mainViewController.view.bounds)) - self.edgeOffset.horizontal, -self.edgeOffset.vertical); + leftCloseTransfrom = CGAffineTransformTranslate(transform, -(CGRectGetMidX(self.mainViewController.view.bounds)) - self.edgeOffset.horizontal, -self.edgeOffset.vertical); + return leftCloseTransfrom; } - (CGAffineTransform)openTransformForView:(UIView *)view From 9a35fee89a73c1154ac8bb278acd4bf759991b12 Mon Sep 17 00:00:00 2001 From: xhzengAIB Date: Sat, 5 Oct 2013 15:32:56 +0000 Subject: [PATCH 2/4] Set gesture distance,but it is not good --- .../project.pbxproj | 1 + .../TWTAppDelegate.m | 2 +- ...WTSideMenuViewController-Sample-Info.plist | 2 +- .../TWTSideMenuViewController.m | 127 +++++++++++++----- 4 files changed, 97 insertions(+), 35 deletions(-) diff --git a/TWTSideMenuViewController-Sample.xcodeproj/project.pbxproj b/TWTSideMenuViewController-Sample.xcodeproj/project.pbxproj index ad28060..d4db2c5 100644 --- a/TWTSideMenuViewController-Sample.xcodeproj/project.pbxproj +++ b/TWTSideMenuViewController-Sample.xcodeproj/project.pbxproj @@ -388,6 +388,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: xianhua zeng (URASQ4RCLH)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "TWTSideMenuViewController-Sample/TWTSideMenuViewController-Sample-Prefix.pch"; INFOPLIST_FILE = "TWTSideMenuViewController-Sample/TWTSideMenuViewController-Sample-Info.plist"; diff --git a/TWTSideMenuViewController-Sample/TWTAppDelegate.m b/TWTSideMenuViewController-Sample/TWTAppDelegate.m index f615204..093d0ae 100644 --- a/TWTSideMenuViewController-Sample/TWTAppDelegate.m +++ b/TWTSideMenuViewController-Sample/TWTAppDelegate.m @@ -32,7 +32,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( self.sideMenuViewController = [[TWTSideMenuViewController alloc] initWithMenuViewController:self.menuViewController mainViewController:[[UINavigationController alloc] initWithRootViewController:self.mainViewController]]; self.sideMenuViewController.shadowColor = [UIColor blackColor]; self.sideMenuViewController.edgeOffset = (UIOffset) { .horizontal = 18.0f }; - self.sideMenuViewController.zoomScale = 0.5634f; + self.sideMenuViewController.zoomScale = 0.65f; self.window.rootViewController = self.sideMenuViewController; self.window.backgroundColor = [UIColor whiteColor]; diff --git a/TWTSideMenuViewController-Sample/TWTSideMenuViewController-Sample-Info.plist b/TWTSideMenuViewController-Sample/TWTSideMenuViewController-Sample-Info.plist index 905fbfe..84e30d0 100644 --- a/TWTSideMenuViewController-Sample/TWTSideMenuViewController-Sample-Info.plist +++ b/TWTSideMenuViewController-Sample/TWTSideMenuViewController-Sample-Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - com.twotoasters.${PRODUCT_NAME:rfc1034identifier} + com.SJQ-IT.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/TWTSideMenuViewController/TWTSideMenuViewController.m b/TWTSideMenuViewController/TWTSideMenuViewController.m index cb4b7ed..1d195c4 100644 --- a/TWTSideMenuViewController/TWTSideMenuViewController.m +++ b/TWTSideMenuViewController/TWTSideMenuViewController.m @@ -104,56 +104,116 @@ - (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { switch (state) { case UIGestureRecognizerStateBegan: case UIGestureRecognizerStateChanged: { - CGFloat xOffset = translation.x; - float scaleOffset = (1.0 - ((xOffset) / self.view.bounds.size.width)); - if (scaleOffset >= self.zoomScale && scaleOffset <= (2.0 - self.zoomScale)) { - if (self.isOpen) { - CGAffineTransform originTransfrom = originScaleTransfrom; - CGAffineTransform scaleTransform = CGAffineTransformScale(originTransfrom, scaleOffset, scaleOffset); - CGAffineTransform openTransfrom = CGAffineTransformTranslate(scaleTransform, xOffset, 0); - self.containerView.transform = openTransfrom; - - self.menuViewController.view.transform = CGAffineTransformTranslate(CGAffineTransformScale(CGAffineTransformIdentity, scaleOffset, scaleOffset), xOffset, 0); - } else { - - - - //main - CGAffineTransform mainPanTransform = CGAffineTransformScale(CGAffineTransformIdentity, scaleOffset, scaleOffset); + if (!self.open) { + CGFloat xOffset = translation.x * 0.9; + + CGFloat width = 857.5; + + float scaleOffset = (1.0 - (xOffset / width)); + + + // 没有打开时候 + if (xOffset > 0) { + // 正常的缩小和向右边移动 // left + CGAffineTransform leftScaleTransform = CGAffineTransformScale(leftCloseTransfrom, scaleOffset - 0.05, scaleOffset - 0.05); - CGAffineTransform leftPanTransform = CGAffineTransformScale(leftCloseTransfrom, scaleOffset, scaleOffset); + CGAffineTransform leftPanGestureTransfrom = CGAffineTransformTranslate(leftScaleTransform, xOffset, 0); + self.menuViewController.view.transform = leftPanGestureTransfrom; - CGAffineTransform translationTransfrom = CGAffineTransformTranslate(leftPanTransform, xOffset, 0); - self.menuViewController.view.transform = translationTransfrom; + // main + CGAffineTransform mainScaleTransfrom = CGAffineTransformScale(CGAffineTransformIdentity, scaleOffset, scaleOffset); + CGAffineTransform mainPanGestureTransfrom = CGAffineTransformTranslate(mainScaleTransfrom, xOffset, 0); + self.containerView.transform = mainPanGestureTransfrom; - self.containerView.transform = CGAffineTransformTranslate(mainPanTransform, xOffset, 0); + } else if (xOffset < 0) { + // 不正常 的放大和向左边移动 } - } else if (xOffset < 300) { - if (self.open) { - if (xOffset > -178) { - CGAffineTransform originTransfrom = originScaleTransfrom; - CGAffineTransform scaleTransform = CGAffineTransformScale(originTransfrom, scaleOffset, scaleOffset); - CGAffineTransform openTransfrom = CGAffineTransformTranslate(scaleTransform, xOffset, 0); - self.containerView.transform = openTransfrom; - } - } else { + + } else { + CGFloat xOffset = translation.x * 0.88; + + CGFloat width = 520.5; + + float scaleOffset = (1.0 - (xOffset / width)); + + // 打开的时候 + if (xOffset > 0) { + // 不正常的缩小和向右边移动 + } else if (xOffset < 0) { + // 正常的放大和向左边移动 + CGAffineTransform originTransfrom = originScaleTransfrom; + CGAffineTransform scaleTransform = CGAffineTransformScale(originTransfrom, scaleOffset, scaleOffset); + CGAffineTransform openTransfrom = CGAffineTransformTranslate(scaleTransform, xOffset * 0.67, 0); + self.containerView.transform = openTransfrom; + + self.menuViewController.view.transform = CGAffineTransformTranslate(CGAffineTransformScale(CGAffineTransformIdentity, scaleOffset, scaleOffset), xOffset * 0.67, 0); - CGAffineTransform panTransform = CGAffineTransformScale(CGAffineTransformIdentity, self.zoomScale, self.zoomScale); - self.containerView.transform = CGAffineTransformTranslate(panTransform, xOffset, 0); } } - + break; } case UIGestureRecognizerStateCancelled: case UIGestureRecognizerStateEnded: { - if ([panGesture velocityInView:panGesture.view].x < 0) { + CGFloat velocityX = [panGesture velocityInView:panGesture.view].x; + if (!self.open) { + // 还没有打开 + if (velocityX > 0) { + // 打开 + [UIView animateWithDuration:0.5 animations:^{ + CGAffineTransform scaleTranfrom = CGAffineTransformTranslate(CGAffineTransformIdentity, 190, 0); + CGAffineTransform openTransfrom = CGAffineTransformScale(scaleTranfrom, self.zoomScale, self.zoomScale); + originScaleTransfrom = openTransfrom; + self.containerView.transform = openTransfrom; + + self.menuViewController.view.transform = CGAffineTransformIdentity; + } completion:^(BOOL finished) { + self.open = finished; + }]; + } else { + // 还原 + [UIView animateWithDuration:0.5 animations:^{ + self.containerView.transform = CGAffineTransformIdentity; + self.menuViewController.view.transform = leftCloseTransfrom; + } completion:^(BOOL finished) { + self.open = !finished; + }]; + } + + } else { + // 已经打开了 + if (velocityX > 0) { + // 还原打开状态 + [UIView animateWithDuration:0.5 animations:^{ + CGAffineTransform scaleTranfrom = CGAffineTransformTranslate(CGAffineTransformIdentity, 178, 0); + CGAffineTransform openTransfrom = CGAffineTransformScale(scaleTranfrom, self.zoomScale, self.zoomScale); + originScaleTransfrom = openTransfrom; + self.containerView.transform = openTransfrom; + + self.menuViewController.view.transform = CGAffineTransformIdentity; + } completion:^(BOOL finished) { + self.open = finished; + }]; + + } else if (velocityX < 0) { + // 关闭left + [UIView animateWithDuration:0.5 animations:^{ + self.containerView.transform = CGAffineTransformIdentity; + self.menuViewController.view.transform = leftCloseTransfrom; + } completion:^(BOOL finished) { + self.open = !finished; + }]; + } + } + + /* + if (velocityX < 0) { // 还原 [UIView animateWithDuration:0.5 animations:^{ @@ -178,6 +238,7 @@ - (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { }]; } + */ break; } default: From 70e9072cda8de63532b9ed7b0d543fa3b771cae9 Mon Sep 17 00:00:00 2001 From: xhzengAIB Date: Sat, 5 Oct 2013 21:01:06 +0000 Subject: [PATCH 3/4] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9B=B4=E5=A5=BD?= =?UTF-8?q?=E7=9A=84=E6=BB=91=E5=8A=A8=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project.pbxproj | 8 + .../TWTMenuViewController.m | 3 +- .../UIView-Transform.h | 29 ++ .../UIView-Transform.m | 269 ++++++++++++++++++ .../TWTSideMenuViewController.m | 241 +++++++--------- 5 files changed, 409 insertions(+), 141 deletions(-) create mode 100755 TWTSideMenuViewController-Sample/UIView-Transform.h create mode 100755 TWTSideMenuViewController-Sample/UIView-Transform.m diff --git a/TWTSideMenuViewController-Sample.xcodeproj/project.pbxproj b/TWTSideMenuViewController-Sample.xcodeproj/project.pbxproj index d4db2c5..0f1c348 100644 --- a/TWTSideMenuViewController-Sample.xcodeproj/project.pbxproj +++ b/TWTSideMenuViewController-Sample.xcodeproj/project.pbxproj @@ -23,6 +23,8 @@ A495C4D717BC109600B880E4 /* TWTMenuViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A495C4D617BC109600B880E4 /* TWTMenuViewController.m */; }; A495C4DA17BC109F00B880E4 /* TWTMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A495C4D917BC109F00B880E4 /* TWTMainViewController.m */; }; A495C4DC17BC11F500B880E4 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A495C4DB17BC11F500B880E4 /* Images.xcassets */; }; + ABED77A018006D5300D92D6F /* UIView-Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = ABED779F18006D5300D92D6F /* UIView-Transform.m */; }; + ABED77A118006D5300D92D6F /* UIView-Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = ABED779F18006D5300D92D6F /* UIView-Transform.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -59,6 +61,8 @@ A495C4D817BC109F00B880E4 /* TWTMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TWTMainViewController.h; sourceTree = ""; }; A495C4D917BC109F00B880E4 /* TWTMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TWTMainViewController.m; sourceTree = ""; }; A495C4DB17BC11F500B880E4 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + ABED779E18006D5300D92D6F /* UIView-Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView-Transform.h"; sourceTree = ""; }; + ABED779F18006D5300D92D6F /* UIView-Transform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView-Transform.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -121,6 +125,8 @@ children = ( A43DC61B17CCE1A500F16C6A /* galaxy.png */, A495C4DB17BC11F500B880E4 /* Images.xcassets */, + ABED779E18006D5300D92D6F /* UIView-Transform.h */, + ABED779F18006D5300D92D6F /* UIView-Transform.m */, A4485E7217BBCA75002B32C4 /* TWTAppDelegate.h */, A4485E7317BBCA75002B32C4 /* TWTAppDelegate.m */, A495C4D517BC109600B880E4 /* TWTMenuViewController.h */, @@ -272,6 +278,7 @@ A4485E7017BBCA75002B32C4 /* main.m in Sources */, A45D359417BBDF6B00BEF872 /* TWTSideMenuViewController.m in Sources */, A495C4D717BC109600B880E4 /* TWTMenuViewController.m in Sources */, + ABED77A018006D5300D92D6F /* UIView-Transform.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -280,6 +287,7 @@ buildActionMask = 2147483647; files = ( A4485E8917BBCA75002B32C4 /* TWTSideMenuViewController_SampleTests.m in Sources */, + ABED77A118006D5300D92D6F /* UIView-Transform.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/TWTSideMenuViewController-Sample/TWTMenuViewController.m b/TWTSideMenuViewController-Sample/TWTMenuViewController.m index d4c8743..63ddcfe 100644 --- a/TWTSideMenuViewController-Sample/TWTMenuViewController.m +++ b/TWTSideMenuViewController-Sample/TWTMenuViewController.m @@ -27,7 +27,8 @@ - (void)viewDidLoad self.backgroundImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"galaxy"]]; CGRect imageViewRect = [[UIScreen mainScreen] bounds]; - imageViewRect.size.width += 589; + imageViewRect.size.width += 909; + imageViewRect.origin.x -= 320; self.backgroundImageView.frame = imageViewRect; self.backgroundImageView.contentMode = UIViewContentModeScaleAspectFit; [self.view addSubview:self.backgroundImageView]; diff --git a/TWTSideMenuViewController-Sample/UIView-Transform.h b/TWTSideMenuViewController-Sample/UIView-Transform.h new file mode 100755 index 0000000..1542063 --- /dev/null +++ b/TWTSideMenuViewController-Sample/UIView-Transform.h @@ -0,0 +1,29 @@ +/* + Erica Sadun, http://ericasadun.com + iPhone Developer's Cookbook, 6.x Edition + BSD License, Use at your own risk + */ + +#import +#import + +@interface UIView (Transform) +@property (nonatomic) CGFloat rotation; +@property (nonatomic) CGFloat xscale; +@property (nonatomic) CGFloat yscale; +@property (nonatomic) CGFloat tx; +@property (nonatomic) CGFloat ty; + +@property (nonatomic, readonly) CGRect originalFrame; +@property (nonatomic, readonly) CGPoint originalCenter; + +@property (nonatomic, readonly) CGPoint transformedTopLeft; +@property (nonatomic, readonly) CGPoint transformedTopRight; +@property (nonatomic, readonly) CGPoint transformedBottomLeft; +@property (nonatomic, readonly) CGPoint transformedBottomRight; + +@property (nonatomic, readonly) NSString *transformDescription; + +- (CGPoint) pointInTransformedView: (CGPoint) pointInParentCoordinates; +- (BOOL) intersectsView: (UIView *) aView; +@end diff --git a/TWTSideMenuViewController-Sample/UIView-Transform.m b/TWTSideMenuViewController-Sample/UIView-Transform.m new file mode 100755 index 0000000..108bdfe --- /dev/null +++ b/TWTSideMenuViewController-Sample/UIView-Transform.m @@ -0,0 +1,269 @@ +/* + Erica Sadun, http://ericasadun.com + iPhone Developer's Cookbook, 6.x Edition + BSD License, Use at your own risk + */ + +#import "UIView-Transform.h" +@implementation UIView (Transform) + +CGAffineTransform makeTransform(CGFloat xScale, CGFloat yScale, CGFloat theta, CGFloat tx, CGFloat ty) +{ + CGAffineTransform transform = CGAffineTransformIdentity; + + transform.a = xScale * cos(theta); + transform.b = yScale * sin(theta); + transform.c = xScale * -sin(theta); + transform.d = yScale * cos(theta); + transform.tx = tx; + transform.ty = ty; + + return transform; +} + +- (CGFloat) xscale +{ + CGAffineTransform t = self.transform; + return sqrt(t.a * t.a + t.c * t.c); +} + +- (void) setXscale: (CGFloat) xScale +{ + self.transform = makeTransform(xScale, self.yscale, self.rotation, self.tx, self.ty); +} + +- (CGFloat) yscale +{ + CGAffineTransform t = self.transform; + return sqrt(t.b * t.b + t.d * t.d); +} + +- (void) setYscale: (CGFloat) yScale +{ + self.transform = makeTransform(self.xscale, yScale, self.rotation, self.tx, self.ty); +} + + +- (CGFloat) rotation +{ + CGAffineTransform t = self.transform; + return atan2f(t.b, t.a); +} + +- (void) setRotation: (CGFloat) theta +{ + self.transform = makeTransform(self.xscale, self.yscale, theta, self.tx, self.ty); +} + + +- (CGFloat) tx +{ + CGAffineTransform t = self.transform; + return t.tx; +} + +- (void) setTx:(CGFloat)tx +{ + self.transform = makeTransform(self.xscale, self.yscale, self.rotation, tx, self.ty); +} + +- (CGFloat) ty +{ + CGAffineTransform t = self.transform; + return t.ty; +} + +- (void) setTy:(CGFloat)ty +{ + self.transform = makeTransform(self.xscale, self.yscale, self.rotation, self.tx, ty); +} + +- (CGPoint) offsetPointToParentCoordinates: (CGPoint) aPoint +{ + return CGPointMake(aPoint.x + self.center.x, aPoint.y + self.center.y); +} + +- (CGPoint) pointInViewCenterTerms: (CGPoint) aPoint +{ + return CGPointMake(aPoint.x - self.center.x, aPoint.y - self.center.y); +} + +- (CGPoint) pointInTransformedView: (CGPoint) aPoint +{ + CGPoint offsetItem = [self pointInViewCenterTerms:aPoint]; + CGPoint updatedItem = CGPointApplyAffineTransform(offsetItem, self.transform); + CGPoint finalItem = [self offsetPointToParentCoordinates:updatedItem]; + + return finalItem; +} + +- (CGRect) originalFrame +{ + CGAffineTransform currentTransform = self.transform; + self.transform = CGAffineTransformIdentity; + CGRect originalFrame = self.frame; + self.transform = currentTransform; + + return originalFrame; +} + +- (CGPoint) originalCenter +{ + CGAffineTransform currentTransform = self.transform; + self.transform = CGAffineTransformIdentity; + CGPoint originalCenter = self.center; + self.transform = currentTransform; + + return originalCenter; +} + +- (NSString *) transformDescription +{ + NSMutableString *descriptionString = [NSMutableString string]; + + [descriptionString appendFormat:@"Frame: %@; ", NSStringFromCGRect(self.originalFrame)]; + [descriptionString appendFormat:@"Transformed Frame: %@; ", NSStringFromCGRect(self.frame)]; + [descriptionString appendFormat:@"Scale: [%0.5f, %0.5f]; ", self.xscale, self.yscale]; + [descriptionString appendFormat:@"Rotation: [%0.5f]; ", self.rotation]; + [descriptionString appendFormat:@"Translation: [%0.5f, %0.5f]; ", self.tx, self.ty]; + [descriptionString appendFormat:@"Transform: %@", CGAffineTransformIsIdentity(self.transform) ? @"Identity" : NSStringFromCGAffineTransform(self.transform)]; + + return descriptionString; +} + +- (CGPoint) transformedTopLeft +{ + CGRect frame = self.originalFrame; + CGPoint point = frame.origin; + return [self pointInTransformedView:point]; +} + +- (CGPoint) transformedTopRight +{ + CGRect frame = self.originalFrame; + CGPoint point = frame.origin; + point.x += frame.size.width; + return [self pointInTransformedView:point]; +} + +- (CGPoint) transformedBottomRight +{ + CGRect frame = self.originalFrame; + CGPoint point = frame.origin; + point.x += frame.size.width; + point.y += frame.size.height; + return [self pointInTransformedView:point]; +} + +- (CGPoint) transformedBottomLeft +{ + CGRect frame = self.originalFrame; + CGPoint point = frame.origin; + point.y += frame.size.height; + return [self pointInTransformedView:point]; +} + +BOOL halfPlane(CGPoint p1, CGPoint p2, CGPoint testPoint) +{ + CGPoint base = CGPointMake(p2.x - p1.x, p2.y - p1.y); + CGPoint orthog = CGPointMake(-base.y, base.x); + return (((orthog.x * (testPoint.x - p1.x)) + (orthog.y * (testPoint.y - p1.y))) >= 0); +} + +BOOL intersectionTest(CGPoint p1, CGPoint p2, UIView *aView) +{ + BOOL tlTest = halfPlane(p1, p2, aView.transformedTopLeft); + BOOL trTest = halfPlane(p1, p2, aView.transformedTopRight); + if (tlTest != trTest) return YES; + + BOOL brTest = halfPlane(p1, p2, aView.transformedBottomRight); + if (tlTest != brTest) return YES; + + BOOL blTest = halfPlane(p1, p2, aView.transformedBottomLeft); + if (tlTest != blTest) return YES; + + return NO; +} + +- (BOOL) intersectsView: (UIView *) aView +{ + if (!CGRectIntersectsRect(self.frame, aView.frame)) return NO; + + CGPoint A = self.transformedTopLeft; + CGPoint B = self.transformedTopRight; + CGPoint C = self.transformedBottomRight; + CGPoint D = self.transformedBottomLeft; + + if (!intersectionTest(A, B, aView)) + { + BOOL test = halfPlane(A, B, aView.transformedTopLeft); + BOOL t1 = halfPlane(A, B, C); + BOOL t2 = halfPlane(A, B, D); + if ((t1 != test) && (t2 != test)) return NO; + } + + if (!intersectionTest(B, C, aView)) + { + BOOL test = halfPlane(B, C, aView.transformedTopLeft); + BOOL t1 = halfPlane(B, C, A); + BOOL t2 = halfPlane(B, C, D); + if ((t1 != test) && (t2 != test)) return NO; + } + + if (!intersectionTest(C, D, aView)) + { + BOOL test = halfPlane(C, D, aView.transformedTopLeft); + BOOL t1 = halfPlane(C, D, A); + BOOL t2 = halfPlane(C, D, B); + if ((t1 != test) && (t2 != test)) return NO; + } + + if (!intersectionTest(D, A, aView)) + { + BOOL test = halfPlane(D, A, aView.transformedTopLeft); + BOOL t1 = halfPlane(D, A, B); + BOOL t2 = halfPlane(D, A, C); + if ((t1 != test) && (t2 != test)) return NO; + } + + A = aView.transformedTopLeft; + B = aView.transformedTopRight; + C = aView.transformedBottomRight; + D = aView.transformedBottomLeft; + + if (!intersectionTest(A, B, self)) + { + BOOL test = halfPlane(A, B, self.transformedTopLeft); + BOOL t1 = halfPlane(A, B, C); + BOOL t2 = halfPlane(A, B, D); + if ((t1 != test) && (t2 != test)) return NO; + } + + if (!intersectionTest(B, C, self)) + { + BOOL test = halfPlane(B, C, self.transformedTopLeft); + BOOL t1 = halfPlane(B, C, A); + BOOL t2 = halfPlane(B, C, D); + if ((t1 != test) && (t2 != test)) return NO; + } + + if (!intersectionTest(C, D, self)) + { + BOOL test = halfPlane(C, D, self.transformedTopLeft); + BOOL t1 = halfPlane(C, D, A); + BOOL t2 = halfPlane(C, D, B); + if ((t1 != test) && (t2 != test)) return NO; + } + + if (!intersectionTest(D, A, self)) + { + BOOL test = halfPlane(D, A, self.transformedTopLeft); + BOOL t1 = halfPlane(D, A, B); + BOOL t2 = halfPlane(D, A, C); + if ((t1 != test) && (t2 != test)) return NO; + } + + return YES; + +} +@end diff --git a/TWTSideMenuViewController/TWTSideMenuViewController.m b/TWTSideMenuViewController/TWTSideMenuViewController.m index 1d195c4..9936fa1 100644 --- a/TWTSideMenuViewController/TWTSideMenuViewController.m +++ b/TWTSideMenuViewController/TWTSideMenuViewController.m @@ -23,20 +23,21 @@ this software and associated documentation files (the "Software"), to deal in #import "TWTSideMenuViewController.h" #import #import +#import "UIView-Transform.h" static NSTimeInterval const kDefaultAnimationDelayDuration = 0.2; -static NSTimeInterval const kDefaultAnimationDuration = 0.4; -static NSTimeInterval const kDefaultSwapAnimationDuration = 0.45; -static NSTimeInterval const kDefaultSwapAnimationClosedDuration = 0.35; +static NSTimeInterval const kDefaultAnimationDuration = 0.5; +static NSTimeInterval const kDefaultSwapAnimationDuration = 0.55; +static NSTimeInterval const kDefaultSwapAnimationClosedDuration = 0.45; @interface TWTSideMenuViewController () { - CGAffineTransform leftCloseTransfrom; + CGAffineTransform menuCloseTransfrom; CGAffineTransform mainOpenTransfrom; CGAffineTransform originScaleTransfrom; } -@property (nonatomic, strong) UIButton *closeOverlayButton; +@property (nonatomic, strong) UIView *closeOverlayView; @property (nonatomic, strong) UIView *containerView; @end @@ -92,10 +93,25 @@ - (void)viewDidLoad [self.view addSubview:self.containerView]; self.menuViewController.view.transform = [self closeTransformForMenuView]; + menuCloseTransfrom = self.menuViewController.view.transform; + + _closeOverlayView = [[UIView alloc] initWithFrame:self.containerView.bounds]; + self.closeOverlayView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.6]; + self.closeOverlayView.alpha = 0.; + [self.view addSubview:self.closeOverlayView]; + + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandle:)]; + [self.closeOverlayView addGestureRecognizer:tapGesture]; } #pragma mark - UIGesture +- (void)tapGestureHandle:(UITapGestureRecognizer *)tapGesture { + if (!self.open) + return ; + [self closeMenuAnimated:YES completion:NULL]; +} + - (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { UIGestureRecognizerState state = panGesture.state; @@ -107,21 +123,17 @@ - (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { if (!self.open) { + // 当Menu关闭的时候 CGFloat xOffset = translation.x * 0.9; - CGFloat width = 857.5; float scaleOffset = (1.0 - (xOffset / width)); - - // 没有打开时候 if (xOffset > 0) { // 正常的缩小和向右边移动 - // left - CGAffineTransform leftScaleTransform = CGAffineTransformScale(leftCloseTransfrom, scaleOffset - 0.05, scaleOffset - 0.05); - - CGAffineTransform leftPanGestureTransfrom = CGAffineTransformTranslate(leftScaleTransform, xOffset, 0); + CGAffineTransform leftScaleTransform = CGAffineTransformScale(menuCloseTransfrom, scaleOffset, scaleOffset); + CGAffineTransform leftPanGestureTransfrom = CGAffineTransformTranslate(leftScaleTransform, xOffset * 0.9, 0); self.menuViewController.view.transform = leftPanGestureTransfrom; // main @@ -129,14 +141,18 @@ - (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { CGAffineTransform mainPanGestureTransfrom = CGAffineTransformTranslate(mainScaleTransfrom, xOffset, 0); self.containerView.transform = mainPanGestureTransfrom; + // 过度的view + CGFloat widthOffset = self.view.bounds.size.width / (UIDeviceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]) ? 4 : 3); + float alphaOffset = (translation.x + widthOffset) / self.view.bounds.size.width; + self.closeOverlayView.alpha = alphaOffset; + self.closeOverlayView.transform = mainPanGestureTransfrom; + } else if (xOffset < 0) { - // 不正常 的放大和向左边移动 + // 不正常的放大和向左边移动 } - } else { CGFloat xOffset = translation.x * 0.88; - CGFloat width = 520.5; float scaleOffset = (1.0 - (xOffset / width)); @@ -144,15 +160,23 @@ - (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { // 打开的时候 if (xOffset > 0) { // 不正常的缩小和向右边移动 + } else if (xOffset < 0) { // 正常的放大和向左边移动 + // left + self.menuViewController.view.transform = CGAffineTransformTranslate(CGAffineTransformScale(CGAffineTransformIdentity, scaleOffset, scaleOffset), xOffset * 0.75, 0); + + // main CGAffineTransform originTransfrom = originScaleTransfrom; CGAffineTransform scaleTransform = CGAffineTransformScale(originTransfrom, scaleOffset, scaleOffset); CGAffineTransform openTransfrom = CGAffineTransformTranslate(scaleTransform, xOffset * 0.67, 0); self.containerView.transform = openTransfrom; - self.menuViewController.view.transform = CGAffineTransformTranslate(CGAffineTransformScale(CGAffineTransformIdentity, scaleOffset, scaleOffset), xOffset * 0.67, 0); - + // 过度的view + CGFloat widthOffset = self.view.bounds.size.width / (UIDeviceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]) ? 4 : 3); + float alphaOffset = (1.0 - (-translation.x + widthOffset) / self.view.bounds.size.width); + self.closeOverlayView.alpha = alphaOffset; + self.closeOverlayView.transform = openTransfrom; } } @@ -162,83 +186,38 @@ - (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { case UIGestureRecognizerStateCancelled: case UIGestureRecognizerStateEnded: { CGFloat velocityX = [panGesture velocityInView:panGesture.view].x; - if (!self.open) { - // 还没有打开 - if (velocityX > 0) { - // 打开 - [UIView animateWithDuration:0.5 animations:^{ - CGAffineTransform scaleTranfrom = CGAffineTransformTranslate(CGAffineTransformIdentity, 190, 0); - CGAffineTransform openTransfrom = CGAffineTransformScale(scaleTranfrom, self.zoomScale, self.zoomScale); - originScaleTransfrom = openTransfrom; - self.containerView.transform = openTransfrom; - - self.menuViewController.view.transform = CGAffineTransformIdentity; - } completion:^(BOOL finished) { - self.open = finished; - }]; + + CGFloat mainViewScale = self.containerView.xscale; + + if (self.open) { + // 已经打开了 + // 1、我只要判断滑动距离为 + if (velocityX <= 0) { + if (mainViewScale >= (1.0 - self.zoomScale) / 3.8 + self.zoomScale) { + self.open = YES; + [self closeMenuAnimated:YES completion:NULL]; + } else { + self.open = NO; + [self openMenuAnimated:YES completion:NULL]; + } } else { - // 还原 - [UIView animateWithDuration:0.5 animations:^{ - self.containerView.transform = CGAffineTransformIdentity; - self.menuViewController.view.transform = leftCloseTransfrom; - } completion:^(BOOL finished) { - self.open = !finished; - }]; + self.open = NO; + [self openMenuAnimated:YES completion:NULL]; } - } else { - // 已经打开了 - if (velocityX > 0) { - // 还原打开状态 - [UIView animateWithDuration:0.5 animations:^{ - CGAffineTransform scaleTranfrom = CGAffineTransformTranslate(CGAffineTransformIdentity, 178, 0); - CGAffineTransform openTransfrom = CGAffineTransformScale(scaleTranfrom, self.zoomScale, self.zoomScale); - originScaleTransfrom = openTransfrom; - self.containerView.transform = openTransfrom; - - self.menuViewController.view.transform = CGAffineTransformIdentity; - } completion:^(BOOL finished) { - self.open = finished; - }]; - - } else if (velocityX < 0) { - // 关闭left - [UIView animateWithDuration:0.5 animations:^{ - self.containerView.transform = CGAffineTransformIdentity; - self.menuViewController.view.transform = leftCloseTransfrom; - } completion:^(BOOL finished) { - self.open = !finished; - }]; + if (velocityX >= 0) { + if (mainViewScale <= (1.0 - self.zoomScale) / 1.2 + self.zoomScale) { + self.open = NO; + [self openMenuAnimated:YES completion:NULL]; + } else { + self.open = YES; + [self closeMenuAnimated:YES completion:NULL]; + } + } else { + self.open = YES; + [self closeMenuAnimated:YES completion:NULL]; } } - - /* - if (velocityX < 0) { - // 还原 - - [UIView animateWithDuration:0.5 animations:^{ - self.containerView.transform = CGAffineTransformIdentity; - self.menuViewController.view.transform = leftCloseTransfrom; - } completion:^(BOOL finished) { - self.open = !finished; - }]; - - } else { - - // 打开 - [UIView animateWithDuration:0.5 animations:^{ - CGAffineTransform scaleTranfrom = CGAffineTransformTranslate(CGAffineTransformIdentity, 178, 0); - CGAffineTransform openTransfrom = CGAffineTransformScale(scaleTranfrom, self.zoomScale, self.zoomScale); - originScaleTransfrom = openTransfrom; - self.containerView.transform = openTransfrom; - - self.menuViewController.view.transform = CGAffineTransformIdentity; - } completion:^(BOOL finished) { - self.open = finished; - }]; - - } - */ break; } default: @@ -272,17 +251,31 @@ - (void)updateStatusBarStyle - (CGAffineTransform)closeTransformForMenuView { - CGFloat transformSize = 1.0f + (1.0f * self.zoomScale); - CGAffineTransform transform = CGAffineTransformScale(self.menuViewController.view.transform, transformSize, transformSize); - leftCloseTransfrom = CGAffineTransformTranslate(transform, -(CGRectGetMidX(self.mainViewController.view.bounds)) - self.edgeOffset.horizontal, -self.edgeOffset.vertical); - return leftCloseTransfrom; + CGAffineTransform originTransfrom = self.menuViewController.view.transform; + CGFloat mainMidX = CGRectGetMidX(self.mainViewController.view.bounds); + CGFloat menuEdgeOffsetHorizontal = self.edgeOffset.horizontal; + CGFloat menuEdgeOffsetVertical = self.edgeOffset.vertical; + + CGFloat tx; + if (originTransfrom.tx != 0) { + tx = -menuCloseTransfrom.tx + originTransfrom.tx; + } else { + tx = (mainMidX + menuEdgeOffsetHorizontal); + } + + CGFloat transformSize = (1.0f + (1.0f * self.zoomScale)) / self.menuViewController.view.transform.a; + CGAffineTransform transform = CGAffineTransformScale(originTransfrom, transformSize, transformSize); + CGAffineTransform tempMenuCloseTransfrom = CGAffineTransformTranslate(transform, -tx, -menuEdgeOffsetVertical); + return tempMenuCloseTransfrom; } - (CGAffineTransform)openTransformForView:(UIView *)view { - CGFloat transformSize = self.zoomScale; - CGAffineTransform newTransform = CGAffineTransformTranslate(view.transform, CGRectGetMidX(self.mainViewController.view.bounds) + self.edgeOffset.horizontal, self.edgeOffset.vertical); - return CGAffineTransformScale(newTransform, transformSize, transformSize); + CGFloat originXScale = view.xscale; + CGFloat transformSize = (self.zoomScale / originXScale); + CGAffineTransform newTransform = CGAffineTransformTranslate(view.transform, CGRectGetMidX(self.mainViewController.view.bounds) + self.edgeOffset.horizontal - view.tx, self.edgeOffset.vertical); + originScaleTransfrom = CGAffineTransformScale(newTransform, transformSize, transformSize); + return originScaleTransfrom; } - (void)openMenuAnimated:(BOOL)animated completion:(void (^)(BOOL finished))completion @@ -295,11 +288,13 @@ - (void)openMenuAnimated:(BOOL)animated completion:(void (^)(BOOL finished))comp void (^openMenuBlock)(void) = ^{ self.menuViewController.view.transform = CGAffineTransformIdentity; self.containerView.transform = [self openTransformForView:self.containerView]; + + self.closeOverlayView.transform = [self openTransformForView:self.closeOverlayView]; + self.closeOverlayView.alpha = 1.0; }; void (^openCompleteBlock)(BOOL) = ^(BOOL finished) { if (finished) { - [self addOverlayButtonToMainViewController]; } if (completion) { @@ -330,11 +325,12 @@ - (void)closeMenuAnimated:(BOOL)animated completion:(void (^)(BOOL finished))com } self.open = NO; - [self removeOverlayButtonFromMainViewController]; - void (^closeMenuBlock)(void) = ^{ self.menuViewController.view.transform = [self closeTransformForMenuView]; self.containerView.transform = CGAffineTransformIdentity; + + self.closeOverlayView.transform = CGAffineTransformIdentity; + self.closeOverlayView.alpha = 0.; }; void (^closeCompleteBlock)(BOOL) = ^(BOOL finished) { @@ -390,22 +386,26 @@ - (void)setMainViewController:(UIViewController *)mainViewController animated:(B } [self addShadowToViewController:incomingViewController]; - [self addViewController:incomingViewController]; [self.containerView addSubview:incomingViewController.view]; incomingViewController.view.frame = self.containerView.bounds; incomingViewController.view.transform = CGAffineTransformTranslate(incomingViewController.view.transform, outgoingStartX, 0.0f); void (^swapChangeBlock)(void) = ^{ + outgoingViewController.view.transform = CGAffineTransformMakeScale(0.85, 0.85); + overlayView.transform = CGAffineTransformMakeScale(0.85, 0.85); + incomingViewController.view.transform = CGAffineTransformIdentity; }; void (^finishedChangeBlock)(BOOL finished) = ^(BOOL finished) { + [self addViewController:incomingViewController]; + [outgoingViewController removeFromParentViewController]; + outgoingViewController.view.transform = CGAffineTransformIdentity; [outgoingViewController.view removeFromSuperview]; [outgoingViewController didMoveToParentViewController:nil]; [overlayView removeFromSuperview]; - [self.closeOverlayButton removeFromSuperview]; self.open = NO; }; @@ -452,45 +452,6 @@ - (void)addShadowToViewController:(UIViewController *)viewController } } -#pragma mark - Overlay button management - -- (void)addOverlayButtonToMainViewController -{ - UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; - button.accessibilityLabel = self.closeOverlayAccessibilityLabel; - button.accessibilityHint = self.closeOverlayAccessibilityHint; - button.backgroundColor = [UIColor clearColor]; - button.opaque = NO; - button.frame = self.containerView.frame; - - [button addTarget:self action:@selector(closeButtonTouchUpInside) forControlEvents:UIControlEventTouchUpInside]; - [button addTarget:self action:@selector(closeButtonTouchedDown) forControlEvents:UIControlEventTouchDown]; - [button addTarget:self action:@selector(closeButtonTouchUpOutside) forControlEvents:UIControlEventTouchUpOutside]; - - [self.view addSubview:button]; - self.closeOverlayButton = button; -} - -- (void)removeOverlayButtonFromMainViewController -{ - [self.closeOverlayButton removeFromSuperview]; -} - -- (void)closeButtonTouchUpInside -{ - [self closeMenuAnimated:YES completion:nil]; -} - -- (void)closeButtonTouchedDown -{ - self.closeOverlayButton.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4]; -} - -- (void)closeButtonTouchUpOutside -{ - self.closeOverlayButton.backgroundColor = [UIColor clearColor]; -} - @end @implementation UIViewController (TWTSideMenuViewController) From 184fcc0d88487c198dcf277734f8fbfb82d38686 Mon Sep 17 00:00:00 2001 From: xhzengAIB Date: Sun, 6 Oct 2013 04:47:47 +0000 Subject: [PATCH 4/4] ViewAppear manager Why don't viewWillAppear and viewDidAppear work normal? TWTMenuViewController should not trigger at the beginning of these two methods, what is wrong? --- .../TWTAppDelegate.m | 26 +- .../TWTMainViewController.m | 18 ++ .../TWTMenuViewController.m | 18 ++ .../TWTSideMenuViewController.h | 12 +- .../TWTSideMenuViewController.m | 303 +++++++++++++++--- .../TWTSideMenuViewController.m.zip | Bin 0 -> 4558 bytes 6 files changed, 313 insertions(+), 64 deletions(-) create mode 100644 TWTSideMenuViewController/TWTSideMenuViewController.m.zip diff --git a/TWTSideMenuViewController-Sample/TWTAppDelegate.m b/TWTSideMenuViewController-Sample/TWTAppDelegate.m index 093d0ae..e1d4b80 100644 --- a/TWTSideMenuViewController-Sample/TWTAppDelegate.m +++ b/TWTSideMenuViewController-Sample/TWTAppDelegate.m @@ -22,20 +22,28 @@ @interface TWTAppDelegate () @implementation TWTAppDelegate +- (TWTMenuViewController *)menuViewController { + if (!_menuViewController) { + _menuViewController = [[TWTMenuViewController alloc] init]; + } + return _menuViewController; +} + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - - self.menuViewController = [[TWTMenuViewController alloc] initWithNibName:nil bundle:nil]; - self.mainViewController = [[TWTMainViewController alloc] initWithNibName:nil bundle:nil]; + self.window.backgroundColor = [UIColor whiteColor]; + + + self.mainViewController = [[TWTMainViewController alloc] init]; + + _sideMenuViewController = [[TWTSideMenuViewController alloc] initWithMenuViewController:self.menuViewController mainViewController:[[UINavigationController alloc] initWithRootViewController:self.mainViewController]]; + _sideMenuViewController.shadowColor = [UIColor blackColor]; + _sideMenuViewController.edgeOffset = (UIOffset) { .horizontal = 18.0f }; + _sideMenuViewController.zoomScale = 0.65f; + self.window.rootViewController = _sideMenuViewController; - self.sideMenuViewController = [[TWTSideMenuViewController alloc] initWithMenuViewController:self.menuViewController mainViewController:[[UINavigationController alloc] initWithRootViewController:self.mainViewController]]; - self.sideMenuViewController.shadowColor = [UIColor blackColor]; - self.sideMenuViewController.edgeOffset = (UIOffset) { .horizontal = 18.0f }; - self.sideMenuViewController.zoomScale = 0.65f; - self.window.rootViewController = self.sideMenuViewController; - self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; } diff --git a/TWTSideMenuViewController-Sample/TWTMainViewController.m b/TWTSideMenuViewController-Sample/TWTMainViewController.m index 9f9f309..c96d745 100644 --- a/TWTSideMenuViewController-Sample/TWTMainViewController.m +++ b/TWTSideMenuViewController-Sample/TWTMainViewController.m @@ -17,6 +17,24 @@ @interface TWTMainViewController () @implementation TWTMainViewController +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + NSLog(@"main viewDidAppear"); +} +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + NSLog(@"main viewWillAppear"); +} + +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + NSLog(@"main viewDidDisappear"); +} +- (void)viewWillDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + NSLog(@"main viewWillDisappear"); +} + - (void)viewDidLoad { [super viewDidLoad]; diff --git a/TWTSideMenuViewController-Sample/TWTMenuViewController.m b/TWTSideMenuViewController-Sample/TWTMenuViewController.m index 63ddcfe..a32809f 100644 --- a/TWTSideMenuViewController-Sample/TWTMenuViewController.m +++ b/TWTSideMenuViewController-Sample/TWTMenuViewController.m @@ -18,6 +18,24 @@ @interface TWTMenuViewController () @implementation TWTMenuViewController +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + NSLog(@"left viewDidAppear"); +} +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + NSLog(@"left viewWillAppear"); +} + +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + NSLog(@"left viewDidDisappear"); +} +- (void)viewWillDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + NSLog(@"left viewWillDisappear"); +} + - (void)viewDidLoad { [super viewDidLoad]; diff --git a/TWTSideMenuViewController/TWTSideMenuViewController.h b/TWTSideMenuViewController/TWTSideMenuViewController.h index 59573b0..28f4959 100644 --- a/TWTSideMenuViewController/TWTSideMenuViewController.h +++ b/TWTSideMenuViewController/TWTSideMenuViewController.h @@ -22,6 +22,12 @@ #import +typedef NS_ENUM(NSInteger,XHDrawerSide){ + XHDrawerSideNone = 0, + XHDrawerSideLeft, + XHDrawerSideRight, +}; + @class TWTSideMenuViewController; @interface TWTSideMenuViewController : UIViewController @@ -42,10 +48,12 @@ @property (nonatomic, strong) UIColor *shadowColor; /** Left side menu view */ -@property (nonatomic, strong) IBOutlet UIViewController *menuViewController; +@property (nonatomic, strong) UIViewController *menuViewController; /** Main View */ -@property (nonatomic, strong) IBOutlet UIViewController *mainViewController; +@property (nonatomic, strong) UIViewController *mainViewController; + +@property (nonatomic, assign, readonly) XHDrawerSide openSide; /** When the menu is opened, a transparent button is displayed over the main view. This property gives the opportunity to modify it's accessibility label. */ @property (nonatomic, copy) NSString *closeOverlayAccessibilityLabel; diff --git a/TWTSideMenuViewController/TWTSideMenuViewController.m b/TWTSideMenuViewController/TWTSideMenuViewController.m index 9936fa1..78f6ed1 100644 --- a/TWTSideMenuViewController/TWTSideMenuViewController.m +++ b/TWTSideMenuViewController/TWTSideMenuViewController.m @@ -25,6 +25,8 @@ this software and associated documentation files (the "Software"), to deal in #import #import "UIView-Transform.h" + + static NSTimeInterval const kDefaultAnimationDelayDuration = 0.2; static NSTimeInterval const kDefaultAnimationDuration = 0.5; static NSTimeInterval const kDefaultSwapAnimationDuration = 0.55; @@ -36,14 +38,24 @@ @interface TWTSideMenuViewController () { CGAffineTransform originScaleTransfrom; } - +@property (nonatomic, assign, readwrite) XHDrawerSide openSide; @property (nonatomic, strong) UIView *closeOverlayView; @property (nonatomic, strong) UIView *containerView; - +@property (nonatomic, strong) UIView * childControllerContainerView; @end @implementation TWTSideMenuViewController +- (UIView *)childControllerContainerView { + if(_childControllerContainerView == nil){ + _childControllerContainerView = [[UIView alloc] initWithFrame:self.view.bounds]; + [_childControllerContainerView setBackgroundColor:[UIColor blackColor]]; + [_childControllerContainerView setAutoresizingMask:UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth]; + [self.view addSubview:_childControllerContainerView]; + } + return _childControllerContainerView; +} + #pragma mark - Life Cycle - (id)initWithCoder:(NSCoder *)aDecoder @@ -59,10 +71,10 @@ - (id)initWithMenuViewController:(UIViewController *)menuViewController mainView { self = [super initWithNibName:nil bundle:nil]; if (self) { - _menuViewController = menuViewController; - _mainViewController = mainViewController; - [self commonInitialization]; + [self setCenterViewController:mainViewController]; + + [self setLeftDrawerViewController:menuViewController]; } return self; } @@ -70,38 +82,196 @@ - (id)initWithMenuViewController:(UIViewController *)menuViewController mainView - (void)commonInitialization { self.animationDuration = kDefaultAnimationDuration; - - [self addViewController:self.menuViewController]; - [self addViewController:self.mainViewController]; + self.edgeOffset = UIOffsetMake(18, 0); + self.zoomScale = 0.65; +} + +#pragma mark - 状态设置 + +-(void)setOpenSide:(XHDrawerSide)openSide{ + if(_openSide != openSide){ + _openSide = openSide; + if(openSide == XHDrawerSideNone){ + [self.menuViewController.view setHidden:YES]; + } + } } #pragma mark - UIViewController +-(void)viewWillAppear:(BOOL)animated{ + [super viewWillAppear:animated]; +} + +-(void)viewDidAppear:(BOOL)animated{ + [super viewDidAppear:animated]; +} + +-(void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; +} + +-(void)viewDidDisappear:(BOOL)animated{ + [super viewDidDisappear:animated]; +} + - (void)viewDidLoad { [super viewDidLoad]; + [self.childControllerContainerView setBackgroundColor:[UIColor blackColor]]; + UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureHandle:)]; [self.view addGestureRecognizer:panGesture]; +} + +#pragma mark - Left Right ViewController manager + +-(void)setRightDrawerViewController:(UIViewController *)rightDrawerViewController{ + [self setDrawerViewController:rightDrawerViewController forSide:XHDrawerSideRight]; +} + +-(void)setLeftDrawerViewController:(UIViewController *)leftDrawerViewController{ + [self setDrawerViewController:leftDrawerViewController forSide:XHDrawerSideLeft]; +} + +- (void)setDrawerViewController:(UIViewController *)viewController forSide:(XHDrawerSide)drawerSide{ + NSParameterAssert(drawerSide != XHDrawerSideNone); - self.menuViewController.view.frame = self.view.bounds; - [self.view addSubview:self.menuViewController.view]; + UIViewController *currentSideViewController = [self sideDrawerViewControllerForSide:drawerSide]; + if (currentSideViewController != nil) { + [currentSideViewController beginAppearanceTransition:NO animated:NO]; + [currentSideViewController.view removeFromSuperview]; + [currentSideViewController endAppearanceTransition]; + [currentSideViewController removeFromParentViewController]; + } - self.containerView = [[UIView alloc] initWithFrame:self.view.bounds]; - self.mainViewController.view.frame = self.containerView.bounds; - [self.containerView addSubview:self.mainViewController.view]; - [self.view addSubview:self.containerView]; - self.menuViewController.view.transform = [self closeTransformForMenuView]; - menuCloseTransfrom = self.menuViewController.view.transform; + UIViewAutoresizing autoResizingMask = 0; + if (drawerSide == XHDrawerSideLeft) { + _menuViewController = viewController; + autoResizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight; + } + else if(drawerSide == XHDrawerSideRight){ + _menuViewController = viewController; + autoResizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight; + } + + if(viewController){ + [self addChildViewController:viewController]; + + if ((self.openSide == drawerSide) && + [self.childControllerContainerView.subviews containsObject:self.containerView]){ + [self.childControllerContainerView insertSubview:viewController.view belowSubview:self.containerView]; + [viewController beginAppearanceTransition:YES animated:NO]; + [viewController endAppearanceTransition]; + } else { + [self.childControllerContainerView addSubview:_menuViewController.view]; + [self.childControllerContainerView sendSubviewToBack:_menuViewController.view]; + } + [viewController didMoveToParentViewController:self]; + [viewController.view setFrame:self.childControllerContainerView.bounds]; + viewController.view.autoresizingMask = autoResizingMask; + viewController.view.transform = [self closeTransformForMenuView]; + menuCloseTransfrom = viewController.view.transform; + } + +} + +-(void)prepareToPresentDrawer:(XHDrawerSide)drawer animated:(BOOL)animated { + XHDrawerSide drawerToHide = XHDrawerSideNone; + if(drawer == XHDrawerSideLeft){ + drawerToHide = XHDrawerSideRight; + } + else if(drawer == XHDrawerSideRight){ + drawerToHide = XHDrawerSideLeft; + } + + UIViewController * sideDrawerViewControllerToPresent = [self sideDrawerViewControllerForSide:drawer]; + UIViewController * sideDrawerViewControllerToHide = [self sideDrawerViewControllerForSide:drawerToHide]; + + [self.childControllerContainerView sendSubviewToBack:sideDrawerViewControllerToHide.view]; + +// [sideDrawerViewControllerToHide.view setHidden:YES]; +// [sideDrawerViewControllerToPresent.view setHidden:NO]; +// [sideDrawerViewControllerToPresent.view setFrame:self.childControllerContainerView.bounds]; + + [sideDrawerViewControllerToPresent beginAppearanceTransition:YES animated:animated]; +} + +#pragma mark - sideDrawerViewController manager + +-(UIViewController*)sideDrawerViewControllerForSide:(XHDrawerSide)drawerSide{ + UIViewController * sideDrawerViewController = nil; + if(drawerSide != XHDrawerSideNone){ + sideDrawerViewController = [self childViewControllerForSide:drawerSide]; + } + return sideDrawerViewController; +} + +-(UIViewController*)childViewControllerForSide:(XHDrawerSide)drawerSide{ + UIViewController * childViewController = nil; + switch (drawerSide) { + case XHDrawerSideLeft: + childViewController = self.menuViewController; + break; + case XHDrawerSideRight: + childViewController = nil; + break; + case XHDrawerSideNone: + childViewController = self.mainViewController; + break; + } + return childViewController; +} + + +#pragma mark - Main ViewController manager + +-(void)setCenterViewController:(UIViewController *)centerViewController{ + [self setCenterViewController:centerViewController animated:NO]; +} + +-(void)setCenterViewController:(UIViewController *)centerViewController animated:(BOOL)animated { + if(_containerView == nil){ + _containerView = [[UIView alloc] initWithFrame:self.view.bounds]; + [self.childControllerContainerView addSubview:self.containerView]; + + if (!_closeOverlayView) { + _closeOverlayView = [[UIView alloc] initWithFrame:self.view.bounds]; + self.closeOverlayView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.6]; + self.closeOverlayView.alpha = 0.; + [self.childControllerContainerView addSubview:self.closeOverlayView]; + + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandle:)]; + [self.closeOverlayView addGestureRecognizer:tapGesture]; + } + } + + UIViewController * oldCenterViewController = self.mainViewController; + if(oldCenterViewController){ + if(animated == NO){ + [oldCenterViewController beginAppearanceTransition:NO animated:NO]; + } + [oldCenterViewController removeFromParentViewController]; + [oldCenterViewController.view removeFromSuperview]; + if(animated == NO){ + [oldCenterViewController endAppearanceTransition]; + } + } + + _mainViewController = centerViewController; - _closeOverlayView = [[UIView alloc] initWithFrame:self.containerView.bounds]; - self.closeOverlayView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.6]; - self.closeOverlayView.alpha = 0.; - [self.view addSubview:self.closeOverlayView]; + [self addChildViewController:self.mainViewController]; + [self.mainViewController.view setFrame:self.containerView.bounds]; + [self.containerView addSubview:self.mainViewController.view]; + [self.mainViewController.view setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight]; - UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandle:)]; - [self.closeOverlayView addGestureRecognizer:tapGesture]; + if(animated == NO) { + [self.mainViewController beginAppearanceTransition:YES animated:NO]; + [self.mainViewController endAppearanceTransition]; + [self.mainViewController didMoveToParentViewController:self]; + } } #pragma mark - UIGesture @@ -119,6 +289,12 @@ - (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { switch (state) { case UIGestureRecognizerStateBegan: + if (!self.open) { + // 当Menu关闭的时候 + [self prepareToPresentDrawer:XHDrawerSideLeft animated:YES]; + } else { + [self.menuViewController beginAppearanceTransition:NO animated:YES]; + } case UIGestureRecognizerStateChanged: { @@ -131,6 +307,8 @@ - (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { if (xOffset > 0) { // 正常的缩小和向右边移动 + + // left CGAffineTransform leftScaleTransform = CGAffineTransformScale(menuCloseTransfrom, scaleOffset, scaleOffset); CGAffineTransform leftPanGestureTransfrom = CGAffineTransformTranslate(leftScaleTransform, xOffset * 0.9, 0); @@ -178,9 +356,7 @@ - (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { self.closeOverlayView.alpha = alphaOffset; self.closeOverlayView.transform = openTransfrom; } - } - break; } case UIGestureRecognizerStateCancelled: @@ -189,7 +365,22 @@ - (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { CGFloat mainViewScale = self.containerView.xscale; - if (self.open) { + if (!self.open) { + // 没有打开 + if (velocityX >= 0) { + if (mainViewScale <= (1.0 - self.zoomScale) / 1.2 + self.zoomScale) { + self.open = NO; + [self openMenuAnimated:YES completion:NULL]; + } else { + self.open = YES; + [self closeMenuAnimated:YES completion:NULL]; + } + } else { + self.open = YES; + [self closeMenuAnimated:YES completion:NULL]; + } + + } else { // 已经打开了 // 1、我只要判断滑动距离为 if (velocityX <= 0) { @@ -198,25 +389,15 @@ - (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { [self closeMenuAnimated:YES completion:NULL]; } else { self.open = NO; + [self.menuViewController beginAppearanceTransition:YES animated:YES]; [self openMenuAnimated:YES completion:NULL]; } } else { self.open = NO; + [self.menuViewController beginAppearanceTransition:YES animated:YES]; [self openMenuAnimated:YES completion:NULL]; } - } else { - if (velocityX >= 0) { - if (mainViewScale <= (1.0 - self.zoomScale) / 1.2 + self.zoomScale) { - self.open = NO; - [self openMenuAnimated:YES completion:NULL]; - } else { - self.open = YES; - [self closeMenuAnimated:YES completion:NULL]; - } - } else { - self.open = YES; - [self closeMenuAnimated:YES completion:NULL]; - } + } break; } @@ -252,7 +433,7 @@ - (void)updateStatusBarStyle - (CGAffineTransform)closeTransformForMenuView { CGAffineTransform originTransfrom = self.menuViewController.view.transform; - CGFloat mainMidX = CGRectGetMidX(self.mainViewController.view.bounds); + CGFloat mainMidX = CGRectGetMidX(self.containerView.bounds); CGFloat menuEdgeOffsetHorizontal = self.edgeOffset.horizontal; CGFloat menuEdgeOffsetVertical = self.edgeOffset.vertical; @@ -285,6 +466,14 @@ - (void)openMenuAnimated:(BOOL)animated completion:(void (^)(BOOL finished))comp } self.open = YES; + UIViewController * sideDrawerViewController = [self sideDrawerViewControllerForSide:XHDrawerSideLeft]; + CGRect visibleRect = CGRectIntersection(self.childControllerContainerView.bounds,sideDrawerViewController.view.frame); + BOOL drawerFullyCovered = (CGRectContainsRect(self.containerView.frame, visibleRect) || + CGRectIsNull(visibleRect)); + if(drawerFullyCovered){ + [self prepareToPresentDrawer:XHDrawerSideLeft animated:animated]; + } + void (^openMenuBlock)(void) = ^{ self.menuViewController.view.transform = CGAffineTransformIdentity; self.containerView.transform = [self openTransformForView:self.containerView]; @@ -295,6 +484,8 @@ - (void)openMenuAnimated:(BOOL)animated completion:(void (^)(BOOL finished))comp void (^openCompleteBlock)(BOOL) = ^(BOOL finished) { if (finished) { + [self.menuViewController endAppearanceTransition]; + [self updateStatusBarStyle]; } if (completion) { @@ -314,8 +505,6 @@ - (void)openMenuAnimated:(BOOL)animated completion:(void (^)(BOOL finished))comp openMenuBlock(); openCompleteBlock(YES); } - - [self updateStatusBarStyle]; } - (void)closeMenuAnimated:(BOOL)animated completion:(void (^)(BOOL finished))completion @@ -325,6 +514,8 @@ - (void)closeMenuAnimated:(BOOL)animated completion:(void (^)(BOOL finished))com } self.open = NO; + [self.menuViewController beginAppearanceTransition:NO animated:YES]; + void (^closeMenuBlock)(void) = ^{ self.menuViewController.view.transform = [self closeTransformForMenuView]; self.containerView.transform = CGAffineTransformIdentity; @@ -335,6 +526,7 @@ - (void)closeMenuAnimated:(BOOL)animated completion:(void (^)(BOOL finished))com void (^closeCompleteBlock)(BOOL) = ^(BOOL finished) { if (finished) { + [self.menuViewController endAppearanceTransition]; [self updateStatusBarStyle]; } @@ -387,13 +579,14 @@ - (void)setMainViewController:(UIViewController *)mainViewController animated:(B [self addShadowToViewController:incomingViewController]; [self.containerView addSubview:incomingViewController.view]; - + incomingViewController.view.frame = self.containerView.bounds; - incomingViewController.view.transform = CGAffineTransformTranslate(incomingViewController.view.transform, outgoingStartX, 0.0f); + CGAffineTransform incomingViewControllerScaleTransfrom = CGAffineTransformScale(incomingViewController.view.transform, 1.2, 1.2); + incomingViewController.view.transform = CGAffineTransformTranslate(incomingViewControllerScaleTransfrom, outgoingStartX, 0.0f); void (^swapChangeBlock)(void) = ^{ - outgoingViewController.view.transform = CGAffineTransformMakeScale(0.85, 0.85); - overlayView.transform = CGAffineTransformMakeScale(0.85, 0.85); + outgoingViewController.view.transform = CGAffineTransformMakeScale(0.65, 0.65); + overlayView.transform = CGAffineTransformMakeScale(0.65, 0.65); incomingViewController.view.transform = CGAffineTransformIdentity; }; @@ -425,16 +618,17 @@ - (void)setMainViewController:(UIViewController *)mainViewController animated:(B } self.mainViewController = mainViewController; - self.mainViewController.sideMenuViewController = self; } #pragma mark - View Management - (void)addViewController:(UIViewController *)viewController { - viewController.sideMenuViewController = self; - [self addChildViewController:viewController]; - [viewController didMoveToParentViewController:self]; + if (viewController) { + viewController.sideMenuViewController = self; + [self addChildViewController:viewController]; + [viewController didMoveToParentViewController:self]; + } } #pragma mark - Shadow management @@ -463,11 +657,14 @@ - (void)setSideMenuViewController:(TWTSideMenuViewController *)sideMenuViewContr - (TWTSideMenuViewController *)sideMenuViewController { - TWTSideMenuViewController *sideMenuController = objc_getAssociatedObject(self, @selector(sideMenuViewController)); - if (!sideMenuController) { - sideMenuController = self.parentViewController.sideMenuViewController; + UIViewController *parentViewController = self.parentViewController; + while (parentViewController != nil) { + if([parentViewController isKindOfClass:[TWTSideMenuViewController class]]){ + return (TWTSideMenuViewController *)parentViewController; + } + parentViewController = parentViewController.parentViewController; } - return sideMenuController; + return nil; } @end diff --git a/TWTSideMenuViewController/TWTSideMenuViewController.m.zip b/TWTSideMenuViewController/TWTSideMenuViewController.m.zip new file mode 100644 index 0000000000000000000000000000000000000000..e31142f7c5875fb6a645d114c31fb2467158f4fc GIT binary patch literal 4558 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 literal 0 HcmV?d00001