diff --git a/TWTSideMenuViewController-Sample.xcodeproj/project.pbxproj b/TWTSideMenuViewController-Sample.xcodeproj/project.pbxproj index ad28060..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; }; @@ -388,6 +396,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..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.5634f; - 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 d4c8743..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]; @@ -27,7 +45,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/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-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.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 d526ec0..78f6ed1 100644 --- a/TWTSideMenuViewController/TWTSideMenuViewController.m +++ b/TWTSideMenuViewController/TWTSideMenuViewController.m @@ -23,21 +23,39 @@ 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; -@interface TWTSideMenuViewController () -@property (nonatomic, strong) UIButton *closeOverlayButton; -@property (nonatomic, strong) UIView *containerView; +static NSTimeInterval const kDefaultAnimationDelayDuration = 0.2; +static NSTimeInterval const kDefaultAnimationDuration = 0.5; +static NSTimeInterval const kDefaultSwapAnimationDuration = 0.55; +static NSTimeInterval const kDefaultSwapAnimationClosedDuration = 0.45; +@interface TWTSideMenuViewController () { + CGAffineTransform menuCloseTransfrom; + CGAffineTransform mainOpenTransfrom; + + 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 @@ -53,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; } @@ -64,26 +82,328 @@ - (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.menuViewController.view.frame = self.view.bounds; - [self.view addSubview:self.menuViewController.view]; + [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); + + UIViewController *currentSideViewController = [self sideDrawerViewControllerForSide:drawerSide]; + if (currentSideViewController != nil) { + [currentSideViewController beginAppearanceTransition:NO animated:NO]; + [currentSideViewController.view removeFromSuperview]; + [currentSideViewController endAppearanceTransition]; + [currentSideViewController removeFromParentViewController]; + } + + + 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; + } - self.containerView = [[UIView alloc] initWithFrame:self.view.bounds]; - self.mainViewController.view.frame = self.containerView.bounds; + 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; + + [self addChildViewController:self.mainViewController]; + [self.mainViewController.view setFrame:self.containerView.bounds]; [self.containerView addSubview:self.mainViewController.view]; - [self.view addSubview:self.containerView]; + [self.mainViewController.view setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight]; + + if(animated == NO) { + [self.mainViewController beginAppearanceTransition:YES animated:NO]; + [self.mainViewController endAppearanceTransition]; + [self.mainViewController didMoveToParentViewController:self]; + } +} + +#pragma mark - UIGesture + +- (void)tapGestureHandle:(UITapGestureRecognizer *)tapGesture { + if (!self.open) + return ; + [self closeMenuAnimated:YES completion:NULL]; +} + +- (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture { + UIGestureRecognizerState state = panGesture.state; - self.menuViewController.view.transform = [self closeTransformForMenuView]; + CGPoint translation = [panGesture translationInView:panGesture.view]; + + switch (state) { + case UIGestureRecognizerStateBegan: + if (!self.open) { + // 当Menu关闭的时候 + [self prepareToPresentDrawer:XHDrawerSideLeft animated:YES]; + } else { + [self.menuViewController beginAppearanceTransition:NO animated:YES]; + } + case UIGestureRecognizerStateChanged: { + + + 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(menuCloseTransfrom, scaleOffset, scaleOffset); + CGAffineTransform leftPanGestureTransfrom = CGAffineTransformTranslate(leftScaleTransform, xOffset * 0.9, 0); + self.menuViewController.view.transform = leftPanGestureTransfrom; + + // main + CGAffineTransform mainScaleTransfrom = CGAffineTransformScale(CGAffineTransformIdentity, scaleOffset, scaleOffset); + 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)); + + // 打开的时候 + 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; + + // 过度的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; + } + } + break; + } + case UIGestureRecognizerStateCancelled: + case UIGestureRecognizerStateEnded: { + CGFloat velocityX = [panGesture velocityInView:panGesture.view].x; + + CGFloat mainViewScale = self.containerView.xscale; + + 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) { + if (mainViewScale >= (1.0 - self.zoomScale) / 3.8 + self.zoomScale) { + self.open = YES; + [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]; + } + + } + break; + } + default: + break; + } } #pragma mark - Status Bar management @@ -112,16 +432,31 @@ - (void)updateStatusBarStyle - (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); + CGAffineTransform originTransfrom = self.menuViewController.view.transform; + CGFloat mainMidX = CGRectGetMidX(self.containerView.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 @@ -131,14 +466,26 @@ - (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]; + + self.closeOverlayView.transform = [self openTransformForView:self.closeOverlayView]; + self.closeOverlayView.alpha = 1.0; }; void (^openCompleteBlock)(BOOL) = ^(BOOL finished) { if (finished) { - [self addOverlayButtonToMainViewController]; + [self.menuViewController endAppearanceTransition]; + [self updateStatusBarStyle]; } if (completion) { @@ -158,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 @@ -169,15 +514,19 @@ - (void)closeMenuAnimated:(BOOL)animated completion:(void (^)(BOOL finished))com } self.open = NO; - [self removeOverlayButtonFromMainViewController]; + [self.menuViewController beginAppearanceTransition:NO animated:YES]; 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) { if (finished) { + [self.menuViewController endAppearanceTransition]; [self updateStatusBarStyle]; } @@ -229,22 +578,27 @@ - (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); + 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.65, 0.65); + overlayView.transform = CGAffineTransformMakeScale(0.65, 0.65); + 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; }; @@ -264,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 @@ -291,45 +646,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) @@ -341,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 0000000..e31142f Binary files /dev/null and b/TWTSideMenuViewController/TWTSideMenuViewController.m.zip differ