Compare commits

...

371 Commits

Author SHA1 Message Date
jonkykong 80a0870606 Path rename 2020-10-19 13:18:39 -07:00
jonkykong 51f6b88d43 Added SwiftUI target 2020-10-19 13:11:13 -07:00
jonkykong 8bd4fd1289 Update podspec 2020-10-17 13:29:41 -07:00
Constantine Loutas 8b71ddf888 Merge pull request #1 from CLoutas/bugfix-crash-on-unwrapping-presentationController
Fix Implicitly Unwrapped Optional Crash on SideMenuAnimationController.swift
2020-08-23 09:42:55 +01:00
Constantine Loutas f09c4d0986 Fix Implicitly Unwrapped Optional Crash
The presentationController variable is declared as an implicitly unwrapped optional (line 38):

private var presentationController: SideMenuPresentationController!

There are situations where this will cause a crash, as the property could be null while transitioning:

Crashed: com.apple.main-thread
0  MyApp                          0x102c57398 closure #1 in SideMenuNavigationController.viewWillTransition(to:with:) + 107 (SideMenuAnimationController.swift:107)
1  MyApp                          0x102c573d0 thunk for @escaping @callee_guaranteed (@guaranteed UIViewControllerTransitionCoordinatorContext) -> () + 4336055248 (<compiler-generated>:4336055248)
2  UIKitCore                      0x1b67c58f4 -[_UIViewControllerTransitionCoordinator _applyBlocks:releaseBlocks:] + 276
3  UIKitCore                      0x1b67c21b4 -[_UIViewControllerTransitionContext __runAlongsideAnimations] + 284
4  UIKitCore                      0x1b67d9b38 -[_UIWindowAnimationController animateTransition:] + 344
5  UIKitCore                      0x1b6e48044 -[UIWindow _adjustSizeClassesAndResizeWindowToFrame:] + 964
6  UIKitCore                      0x1b6e546b4 -[UIWindow _resizeWindowFrameToSceneBoundsIfNecessary] + 252
7  UIKitCore                      0x1b6e4a26c __78-[UIWindow _rotateWindowToOrientation:updateStatusBar:duration:skipCallbacks:]_block_invoke + 408
8  UIKitCore                      0x1b67da1e8 __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke_2 + 180
9  UIKitCore                      0x1b72d0e48 +[UIView(Internal) _performBlockDelayingTriggeringResponderEvents:forScene:] + 212
10 UIKitCore                      0x1b67d9fd4 __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke + 180
11 UIKitCore                      0x1b67d9e98 -[_UIWindowRotationAnimationController animateTransition:] + 524
12 UIKitCore                      0x1b6e478c4 -[UIWindow _rotateToBounds:withAnimator:transitionContext:] + 624
13 UIKitCore                      0x1b6e49f74 -[UIWindow _rotateWindowToOrientation:updateStatusBar:duration:skipCallbacks:] + 1436
14 UIKitCore                      0x1b6e4a4b0 -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:isRotating:] + 404
15 UIKitCore                      0x1b6e49844 -[UIWindow _setRotatableViewOrientation:updateStatusBar:duration:force:] + 132
16 UIKitCore                      0x1b66bf2dc -[_UIFullscreenPresentationController _placeCounterRotationViewWithView:inWindow:fromOrientation:toOrientation:force:] + 520
17 UIKitCore                      0x1b66bf010 -[_UIFullscreenPresentationController _adjustOrientationIfNecessaryInWindow:forViewController:preservingViewController:] + 908
18 UIKitCore                      0x1b66b45ec -[UIPresentationController _presentWithAnimationController:interactionController:target:didEndSelector:] + 900
19 UIKitCore                      0x1b67a8590 -[UIViewController _presentViewController:modalSourceViewController:presentationController:animationController:interactionController:completion:] + 1416
20 UIKitCore                      0x1b67a9f74 -[UIViewController _presentViewController:withAnimationController:completion:] + 4212
21 UIKitCore                      0x1b67ac540 __63-[UIViewController _presentViewController:animated:completion:]_block_invoke + 108
22 UIKitCore                      0x1b67aca94 -[UIViewController _performCoordinatedPresentOrDismiss:animated:] + 528
23 UIKitCore                      0x1b67ac48c -[UIViewController _presentViewController:animated:completion:] + 212
24 UIKitCore                      0x1b67ac720 -[UIViewController presentViewController:animated:completion:] + 176
25 UIKitCore                      0x1b6f6f9b8 __74-[UIStoryboardPresentationSegueTemplate newDefaultPerformHandlerForSegue:]_block_invoke + 148
26 UIKitCore                      0x1b6f75a18 -[UIStoryboardSegueTemplate _performWithDestinationViewController:sender:] + 296
27 UIKitCore                      0x1b6f758bc -[UIStoryboardSegueTemplate _perform:] + 96
28 UIKitCore                      0x1b6f75b98 -[UIStoryboardSegueTemplate perform:] + 164
29 UIKitCore                      0x1b6e086c0 -[UIApplication sendAction:to:from:forEvent:] + 100
30 UIKitCore                      0x1b6479858 __45-[_UIButtonBarTargetAction _invoke:forEvent:]_block_invoke + 84
31 UIKitCore                      0x1b64796e4 -[_UIButtonBarTargetAction _invoke:forEvent:] + 256
32 UIKitCore                      0x1b6e086c0 -[UIApplication sendAction:to:from:forEvent:] + 100
33 UIKitCore                      0x1b67f0b30 -[UIControl sendAction:to:forEvent:] + 208
34 UIKitCore                      0x1b67f0e98 -[UIControl _sendActionsForEvents:withEvent:] + 400
35 UIKitCore                      0x1b67efeb0 -[UIControl touchesEnded:withEvent:] + 520
36 UIKitCore                      0x1b6e43b08 -[UIWindow _sendTouchesForEvent:] + 1024
37 UIKitCore                      0x1b6e452f0 -[UIWindow sendEvent:] + 3548
38 UIKitCore                      0x1b6e2045c -[UIApplication sendEvent:] + 348
39 UIKitCore                      0x1b6ea3a54 __dispatchPreprocessedEventFromEventQueue + 6688
40 UIKitCore                      0x1b6ea6648 __handleEventQueueInternal + 5368
41 UIKitCore                      0x1b6e9e578 __handleHIDEventFetcherDrain + 144
42 CoreFoundation                 0x1b2c39af4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
43 CoreFoundation                 0x1b2c39a48 __CFRunLoopDoSource0 + 84
44 CoreFoundation                 0x1b2c39198 __CFRunLoopDoSources0 + 196
45 CoreFoundation                 0x1b2c33f38 __CFRunLoopRun + 796
46 CoreFoundation                 0x1b2c338f4 CFRunLoopRunSpecific + 480
47 GraphicsServices               0x1bd04a604 GSEventRunModal + 164
48 UIKitCore                      0x1b6e07358 UIApplicationMain + 1944
49 MyApp                          0x102921628 main + 15 (AppDelegate.swift:15)
50 libdyld.dylib                  0x1b2aaf2dc start + 4

By making it a normal optional, we can avoid such crashes.
2020-08-23 09:39:02 +01:00
Jon Kent 38aa59c003 Create FUNDING.yml 2020-07-24 23:39:03 -07:00
jonkykong be2ac457c1 Change default behavior of statusBarEndAlpha as its caused confusion for users who haven't read the documentation. 2020-07-23 19:00:12 -07:00
jonkykong c451180c26 Updated cocoapods 2020-07-23 18:16:45 -07:00
jonkykong 224581cac8 Updated podspec 2020-07-23 17:51:27 -07:00
jonkykong 2f4d99a03c Minor bugfix for interactive pop gesture settings getting overwritten 2020-07-23 17:50:47 -07:00
jonkykong e10c8b8d51 Switch to safer weak declarations to avoid memory access crashes 2020-07-23 17:50:19 -07:00
jonkykong 8314bde8e0 Comment spelling correction 2020-07-23 17:41:28 -07:00
jonkykong 1381030931 Updated podspec 2020-03-26 13:24:24 -07:00
jonkykong 7fc34c74ed Updated local pods 2020-03-26 13:19:24 -07:00
jonkykong 66cb4a2d4b Merge branch '6.4.8' into circular-reference-fix
* 6.4.8:
  Reran pod install to correct issues with running demo project
  Minor refactor
2020-03-26 13:18:43 -07:00
carlos 18a6f1d229 add xcode 11.4 support 2020-03-05 18:10:23 +01:00
jonkykong d593da496b Reran pod install to correct issues with running demo project 2019-12-03 11:02:29 -08:00
jonkykong 537f39373c Minor refactor 2019-12-03 10:55:46 -08:00
jonkykong 73be895065 Updated podspec 2019-11-20 01:54:23 -08:00
jonkykong 00003f098f Fix for animation flash when dismissing modal view controller over SideMenu 2019-11-20 01:43:12 -08:00
jonkykong f4b74330c0 Minor refactor 2019-11-20 01:35:23 -08:00
jonkykong fb25017bc7 Updated podspec 2019-10-31 17:37:16 -07:00
jonkykong 1841827ef9 Fix for interactive regression 2019-10-30 11:36:40 -07:00
jonkykong a5852d8fd0 Refactor 2019-10-30 11:36:15 -07:00
jonkykong 3e4e829ce0 Updated podspec 2019-10-27 23:59:58 -07:00
jonkykong 43d1768175 Fix for in-call status bar height on iOS 12 and lower. 2019-10-27 16:10:21 -07:00
jonkykong 8ecc8ab441 Refactor to move view hierarchy logic out of the presentation controller and into the animation controller. Not moving it to the transition controller since it needs to happen before the animation is fully completed. 2019-10-27 16:09:54 -07:00
jonkykong 4b01b0f874 Update cocoapods and project settings 2019-10-27 16:01:40 -07:00
jonkykong 6b7de92136 Refactor 2019-10-27 16:01:18 -07:00
jonkykong f3c4a22931 Refactor 2019-10-16 23:07:03 -07:00
jonkykong 46c40f081a Refactor 2019-10-16 23:04:45 -07:00
jonkykong 3659e868be Refactor 2019-10-16 22:59:28 -07:00
jonkykong 4e7a35f0b8 Updated cocoapods 2019-10-16 22:56:13 -07:00
jonkykong 082813937e Updated podspec 2019-10-10 21:13:00 -07:00
jonkykong 538e84a26d Updated tests 2019-10-10 21:10:55 -07:00
jonkykong 17b8fcd413 Updated podspec 2019-09-29 13:06:08 -07:00
jonkykong 64f9d0bfbd Bug fix 2019-09-29 13:05:56 -07:00
jonkykong 8dde1951c3 Updated podspec 2019-09-26 01:16:30 -07:00
jonkykong 7d15070513 Scope adjustment 2019-09-26 01:16:14 -07:00
jonkykong b76a39208e Merge branch 'master' of https://github.com/jonkykong/SideMenu
* 'master' of https://github.com/jonkykong/SideMenu:
  Update README.md
2019-09-26 01:15:54 -07:00
Jon Kent 2c496c3c56 Update README.md 2019-09-25 02:17:29 -07:00
jonkykong 37071b5d06 Updated podspec 2019-09-24 22:38:42 -07:00
jonkykong 607260ac2e Fix for view controller views now being clipped causing shadows not to work. 2019-09-24 22:38:27 -07:00
jonkykong 9f3759c90c Updated podspec 2019-09-24 03:07:11 -07:00
jonkykong c346f2e0db Minor refactor 2019-09-24 03:06:02 -07:00
jonkykong 6c72727408 iOS 13 support 2019-09-24 03:05:48 -07:00
jonkykong b649404a7e Refactor 2019-09-21 23:34:26 -07:00
jonkykong 3272a0f63e Refactor 2019-09-21 18:03:30 -07:00
jonkykong 70fa815037 Refactor 2019-09-21 18:03:09 -07:00
jonkykong 794767455a Updated podspec 2019-09-19 00:26:03 -07:00
Matteo Piccina 7359ee6801 Update Package.swift 2019-09-15 15:10:29 +02:00
jonkykong 0b62749bff Updated podspec 2019-09-13 01:49:20 -07:00
Jon Kent 7179713c18 Update README.md 2019-09-13 01:37:51 -07:00
Jon Kent 60f6f204c1 Update README.md 2019-09-13 01:27:26 -07:00
jonkykong 98c5b2b3e3 Updated podspec 2019-09-13 01:12:00 -07:00
jonkykong e8882a952d Reverting swift 4.2 changes. 2019-09-13 01:11:46 -07:00
jonkykong efc2e11fb2 Refactor 2019-09-13 01:10:51 -07:00
jonkykong 36662fa0f3 Merge branch 'pr/540' into 6.2.9
* pr/540:
  Fix File Reference to SideMenu.h
2019-09-13 00:58:08 -07:00
Alex Leeds dce89eb448 Fix File Reference to SideMenu.h 2019-09-11 10:41:21 -04:00
Rafael Francisco 32f1101e86 Fixed notification names 2019-09-10 14:17:50 +01:00
Rafael Francisco d25de76a92 Added SwiftPM support 2019-09-06 15:24:53 +01:00
jonkykong 59faed8ef9 Update podspec 2019-09-06 03:02:08 -07:00
jonkykong 4f990e86a8 Fix and refactor 2019-09-06 03:01:51 -07:00
jonkykong 8200e0d49f correction 2019-09-06 00:09:05 -07:00
jonkykong 5bb2f86b0a Updated podspec 2019-09-06 00:05:52 -07:00
jonkykong c591059fbe Crash fix 2019-09-06 00:05:39 -07:00
jonkykong cf6ec23a7f File structure reorganization 2019-09-05 02:28:46 -07:00
jonkykong 21a7347079 Refactor 2019-09-05 02:18:08 -07:00
jonkykong fc593b0cb7 Cleanup 2019-09-05 02:13:13 -07:00
jonkykong 55bfef578c Cleanup 2019-09-05 02:07:49 -07:00
jonkykong 620b248799 Cleanup 2019-09-05 02:04:47 -07:00
jonkykong 279ba484d3 Fix build issues 2019-09-05 02:01:17 -07:00
jonkykong c46745cef8 Refactor 2019-09-04 23:42:02 -07:00
jonkykong 8cc163dc5f Updated podspec 2019-09-04 23:36:33 -07:00
jonkykong fae34995ab Refactoring 2019-09-04 23:31:08 -07:00
jonkykong 90878cc0d5 Updated podspec 2019-09-04 01:42:39 -07:00
jonkykong 3f78b9bb49 Refactor 2019-09-04 01:40:44 -07:00
Jon Kent 6f8f224e00 Update README.md 2019-08-28 17:28:58 -07:00
jonkykong bc37f1b9cb Updated podspec 2019-08-25 21:07:17 -07:00
jonkykong 8aff2b3627 Merge tag '6.2.3' into 6.2.4
* tag '6.2.3':
  Updated podspec
  Propagate configured onTopShadowOffset to layer
2019-08-25 21:06:55 -07:00
jonkykong 135a3d2a94 Updated podspec 2019-08-20 23:15:01 -07:00
Marius Rackwitz a10b94e351 Propagate configured onTopShadowOffset to layer 2019-08-20 12:50:25 +02:00
Artur Azarau e1bf7c4991 delegate was made public 2019-08-19 14:08:54 +03:00
jonkykong b19c93ff2c Updated podspec 2019-08-17 10:59:18 -07:00
jonkykong 3968686410 Storyboard fix 2019-08-17 10:59:04 -07:00
jonkykong 0a457b414e Updated podspec 2019-08-14 02:20:38 -07:00
jonkykong 5abf5ca740 Updated screenshot 2019-08-14 02:20:25 -07:00
jonkykong 498669bf58 Updated README 2019-08-14 02:16:18 -07:00
jonkykong 159c87871b Expanded renaming to include delegates 2019-08-14 02:16:02 -07:00
jonkykong 4c0733d82a Updated podspec 2019-08-14 01:24:08 -07:00
jonkykong c3671408da Renamed and deprecated UISideMenuNavigationController to SideMenuNavigationController 2019-08-14 01:23:55 -07:00
jonkykong 3268b15e54 Marked InitializableClass as internal 2019-08-14 01:23:08 -07:00
jonkykong 22a7723345 Updated podspec 2019-08-11 10:15:08 -07:00
jonkykong 423b56b9ac Fix for dismiss not working when menu is revealed interactively 2019-08-11 10:09:09 -07:00
Jon Kent 06fbf875d0 Update README.md 2019-08-11 01:07:55 -07:00
jonkykong 9d9c22c786 Updated tests 2019-08-11 01:06:29 -07:00
jonkykong de1b010ac1 Added shared scheme 2019-08-10 23:47:52 -07:00
jonkykong d061bd178d Updated circle config 2019-08-10 23:12:18 -07:00
jonkykong 93ddab1377 Updated circle config 2019-08-10 20:27:47 -07:00
jonkykong 60854beac1 Added basic support for CircleCI 2019-08-10 20:05:17 -07:00
jonkykong 2e8740a91e Update podspec 2019-08-07 01:39:23 -07:00
jonkykong b387ef2dd7 Merge branch 'pr/524' into 6.1.4
* pr/524:
  Refactor
  Added isHidden property for public usage
2019-08-07 01:38:41 -07:00
jonkykong 22596320a3 Refactor 2019-08-07 01:38:28 -07:00
jonkykong 9363b747d1 Push logic fix 2019-08-07 01:31:22 -07:00
Mykola Vaniurskyi baae6186d7 Added isHidden property for public usage 2019-08-06 16:10:20 +03:00
jonkykong c5f80f954c Updated podspec version 2019-08-05 00:30:31 -07:00
jonkykong 493fa9a7a1 Updated podspec for swift version 2019-08-05 00:29:25 -07:00
jonkykong 2de8d7f758 Minor refactoring 2019-08-02 03:12:04 -07:00
jonkykong 62a37e20d1 Merge branch 'master' into 6.1.2
* master:
  Update README.md
2019-07-31 00:39:12 -07:00
jonkykong 7a799b94a8 Updated podspec 2019-07-31 00:38:36 -07:00
jonkykong 3a01ab6398 Fix for programmatic dismissal of menu after being interactively exposed. 2019-07-31 00:37:57 -07:00
Jon Kent 5e4ab5e254 Update README.md 2019-07-29 15:34:58 -07:00
jonkykong 70715d6fa0 Updated podspec 2019-07-29 00:57:22 -07:00
jonkykong 411bd59493 Refactor 2019-07-29 00:56:05 -07:00
jonkykong 5e295d36eb Fix for gesture cancelation causing menu unresponsiveness 2019-07-29 00:53:21 -07:00
jonkykong 6aa68df4ce Update podspec 2019-07-28 23:05:46 -07:00
jonkykong 5c292125a6 Fix for tap gesture not working in landscape mode 2019-07-28 23:04:34 -07:00
jonkykong 48eb4a2e3a Fix for delegate not always being called 2019-07-28 23:04:18 -07:00
jonkykong 9503c814d6 README update 2019-07-28 23:03:59 -07:00
jonkykong 4dd4f54a8e Refactor + add support for tap gesture option 2019-07-28 23:03:41 -07:00
jonkykong 7429a42c26 Fix for landscape mode menu tap to dismiss 2019-07-28 16:05:49 -07:00
jonkykong df032e6072 Fix for updating UI in demo project 2019-07-28 16:05:23 -07:00
jonkykong 3a7c74e2e0 Fix for viewWillDisappear not being called 2019-07-27 03:28:14 -07:00
jonkykong 900926f268 Updated strings 2019-07-27 03:27:46 -07:00
jonkykong f5e585857c Updated documentation 2019-07-27 03:27:24 -07:00
Mikhail Apurin 1d96ef80b3 Unreliable dismissal by tap gesture 2019-07-25 16:50:11 +09:00
Jon Kent 452b354e19 Update README.md 2019-07-24 10:20:04 -07:00
jonkykong 78a3a66a69 Updated podspec 2019-07-23 01:41:18 -07:00
jonkykong 8fe0a23a38 Auto-assignment of leftSide property from SideMenuManager 2019-07-23 01:40:35 -07:00
jonkykong 3a873661c3 Refactor 2019-07-23 00:58:06 -07:00
jonkykong 89fc05a324 Example project fix 2019-07-23 00:55:16 -07:00
jonkykong 453e110246 Refactor 2019-07-23 00:55:02 -07:00
jonkykong b39142bc1a Updated podspec 2019-07-22 01:13:26 -07:00
jonkykong a6bd743e99 README correction 2019-07-22 01:13:15 -07:00
jonkykong 749588918c Logic correction 2019-07-22 01:13:02 -07:00
jonkykong f5b6615c72 Podspec update 2019-07-21 21:44:17 -07:00
jonkykong 8804675b80 Demo project correction 2019-07-21 21:43:42 -07:00
jonkykong b0a09a5b7d Fix for layout when menu not dismissed during presentation 2019-07-21 21:43:25 -07:00
jonkykong f1e4efeb46 Refactor 2019-07-21 21:43:07 -07:00
jonkykong aea7592d85 Scope change 2019-07-19 00:49:26 -07:00
jonkykong 87edaf1d32 Update podspec 2019-07-19 00:32:22 -07:00
jonkykong d14a8d66b3 Tighten up gesture logic 2019-07-19 00:30:01 -07:00
jonkykong 36e8131965 Layering fix 2019-07-19 00:14:57 -07:00
jonkykong 58318a638d Example project fix 2019-07-19 00:14:31 -07:00
jonkykong 06ea874cc6 Updated podspec 2019-07-18 00:16:50 -07:00
jonkykong fd8437b181 Cleaned up deprecations 2019-07-18 00:16:25 -07:00
Jon Kent 8c0d6b636f Update Deprecations.swift 2019-07-17 16:22:08 -07:00
jonkykong 44d1de7d48 Upped podspec 2019-07-17 09:44:50 -07:00
jonkykong 287434b008 Refactor 2019-07-17 09:44:33 -07:00
jonkykong c0ec53608f Fix for unresponsive presentation 2019-07-17 09:36:55 -07:00
jonkykong 54a9f3887d Fix for programmatic instantiation not calling setup() 2019-07-17 02:49:10 -07:00
jonkykong 82b3e95c29 Upped podspec 2019-07-16 02:38:34 -07:00
jonkykong 7ffe987e96 Fix to build all schemes 2019-07-16 02:38:22 -07:00
jonkykong 14ddcaa1cb Upped podspec 2019-07-16 02:28:05 -07:00
jonkykong e94153ce25 Crash fix 2019-07-16 02:25:40 -07:00
jonkykong b9a5ed0886 Refactor 2019-07-16 02:25:00 -07:00
Jon Kent b2c8bedaca Update README.md 2019-07-14 13:37:41 -07:00
Jon Kent e94de73713 Update README.md 2019-07-14 13:23:37 -07:00
Jon Kent b43f4d14f3 Update README.md 2019-07-14 13:22:05 -07:00
jonkykong b99f694129 pod install 2019-07-14 12:53:20 -07:00
jonkykong 0ede564456 Updated podspec 2019-07-14 12:48:04 -07:00
jonkykong dc059ce7d6 Renames, bug fixes 2019-07-14 03:39:50 -07:00
jonkykong 09b0f3b6f0 Merge branch 'major-refactor' of https://github.com/jonkykong/SideMenu into major-refactor 2019-07-14 02:17:52 -07:00
jonkykong 24141cb436 Refactoring, comments, renaming 2019-07-14 02:17:17 -07:00
Jon Kent ec00f3fb2b Update README.md 2019-07-14 02:06:58 -07:00
Jon Kent 71f3d30efa Update README.md 2019-07-14 02:05:16 -07:00
Jon Kent 4ccb12cbd3 Update README.md 2019-07-13 23:35:55 -07:00
Jon Kent 37b67786c6 Update README.md 2019-07-06 00:36:50 -07:00
jonkykong 37e9afc475 Merge branch 'major-refactor' of https://github.com/jonkykong/SideMenu into major-refactor
* 'major-refactor' of https://github.com/jonkykong/SideMenu:
  Update README.md
  Update README.md
  Update README.md
2019-07-06 00:04:06 -07:00
jonkykong c91995c71c Update comments 2019-07-06 00:03:53 -07:00
Jon Kent 0d3780fecc Update README.md 2019-07-05 23:18:57 -07:00
Jon Kent 1f37d83568 Update README.md 2019-07-05 23:15:48 -07:00
Jon Kent f3c00687aa Update README.md 2019-07-05 23:11:25 -07:00
jonkykong 058593a6fc Merge branch 'major-refactor' of https://github.com/jonkykong/SideMenu into major-refactor
* 'major-refactor' of https://github.com/jonkykong/SideMenu:
  Update README.md
  Update README.md
  Update README.md
  Update README.md
  Update README.md
  Update README.md
2019-07-05 22:51:20 -07:00
jonkykong 9f4bc56e43 Scoping and reorganization 2019-07-05 22:50:49 -07:00
Jon Kent d9229e68e9 Update README.md 2019-07-05 22:46:32 -07:00
Jon Kent 53a7bd4b05 Update README.md 2019-07-05 22:46:09 -07:00
Jon Kent d59ca607e0 Update README.md 2019-07-05 22:28:58 -07:00
Jon Kent 54c6980a05 Update README.md 2019-07-05 22:26:10 -07:00
Jon Kent 5a45d4ca0f Update README.md 2019-07-05 22:22:49 -07:00
Jon Kent 8e7bf66dba Update README.md 2019-07-05 20:45:25 -07:00
jonkykong 3aad126881 Added comment and init 2019-07-05 20:20:07 -07:00
jonkykong 6ef3315306 Minor refactoring 2019-07-05 18:53:05 -07:00
jonkykong 2cea3499ee Added deprecations 2019-07-05 15:18:30 -07:00
jonkykong 77d5a9acbe Refactoring 2019-07-03 00:58:31 -07:00
jonkykong f641e674db Refactoring 2019-07-02 01:25:29 -07:00
jonkykong f5aa75c082 Refactoring 2019-06-27 01:50:02 -07:00
jonkykong a38315d17a Refactor 2019-05-13 00:39:26 -07:00
jonkykong 89f0a781d7 Refactoring 2019-05-12 23:12:14 -07:00
jonkykong e79d59e8ec Refactor 2019-05-07 21:39:48 -07:00
jonkykong f560687c91 Silence warnings 2019-04-03 01:06:14 -07:00
jonkykong 392be96c1a In flight changes 2019-02-24 14:10:04 -08:00
Jon Kent 3ca1801cfd Update issue templates 2018-12-14 14:51:47 -08:00
Jon Kent 0330adf802 Update issue templates 2018-12-14 14:49:17 -08:00
jonkykong 3a18cb2b07 Update README for Github. 2018-11-06 00:19:27 -08:00
jonkykong c7f2b8d319 Update README for Cocoapods. 2018-11-06 00:08:42 -08:00
Valeriy Van 7f1cd5b12a Fixes Podfile adding platform and removing missing target 2018-10-25 11:29:51 +02:00
Jon Kent f890891006 Update README.md 2018-10-16 01:44:27 -07:00
jonkykong 1e1984aa73 Revert README for Github. 2018-10-16 01:30:12 -07:00
jonkykong 0d7cca5609 Update README for Cocoapods 2018-10-16 01:26:49 -07:00
jonkykong 9dcfc25b48 Remove swift version file. 2018-10-16 01:24:59 -07:00
jonkykong 017e97db18 Update podspec version. 2018-10-16 01:22:12 -07:00
jonkykong fbcee66c14 Merge branch 'pr/412' into 5.0.2
* pr/412:
  Refactor
  fix: makes dismissWhenInBackground to be computed property of SideMenuManager
  Adds mainViewController.view to originalSuperview only if dismissWhenInBackground is true
  Prevents fadeout transition if 'dismissWhenInBackground' is set to false
  Adds ability to toggle automatic dismissal of the menu when app goes to the background
2018-10-16 01:17:02 -07:00
jonkykong ad47e8bff1 Refactor 2018-10-16 01:13:38 -07:00
jonkykong b4042a562d Update podspec 2018-10-16 00:46:12 -07:00
Igor Kravchenko c7c6fdf64a fix: makes dismissWhenInBackground to be computed property of SideMenuManager 2018-10-10 17:46:42 +03:00
Igor Kravchenko 02595f2b68 Adds mainViewController.view to originalSuperview only if dismissWhenInBackground is true 2018-10-10 15:16:03 +03:00
Igor Kravchenko a8f0d75e66 Prevents fadeout transition if 'dismissWhenInBackground' is set to false 2018-10-10 13:23:22 +03:00
Igor Kravchenko fbe29c7756 Adds ability to toggle automatic dismissal of the menu when app goes to the background 2018-10-10 12:59:25 +03:00
Jon Kent 61f1556d93 Update README.md 2018-10-09 17:40:34 -07:00
Jon Kent ceb3e44c31 Update README.md 2018-09-26 13:31:17 -07:00
Jon Kent 01987a9d5b Update README.md 2018-09-25 11:29:46 -07:00
jonkykong b1e83dc4a8 Update README for Github. 2018-09-25 11:22:36 -07:00
jonkykong 89d3048c09 Merge tag '5.0.1'
* tag '5.0.1':
  Updated podspec.
  Update README for Cocoapods.
  Fixes to fully upgrade to Swift 4.2 as it appears to have been incomplete.
2018-09-25 11:21:51 -07:00
jonkykong ddca756462 Updated podspec. 2018-09-25 11:18:53 -07:00
jonkykong 1ebd491f04 Updated podspec. 2018-09-25 10:58:29 -07:00
jonkykong ad9fa96e33 Update README for Cocoapods. 2018-09-25 10:58:07 -07:00
jonkykong a2370c8cb4 Fixes to fully upgrade to Swift 4.2 as it appears to have been incomplete. 2018-09-25 10:57:23 -07:00
jonkykong 8f995c2bc6 Revert README for Github. 2018-09-25 03:02:31 -07:00
jonkykong 202289d5c6 Updated README. 2018-09-25 02:58:18 -07:00
jonkykong f71245ed75 Update iOS minimum supported version and README. 2018-09-25 02:52:34 -07:00
jonkykong ba3703abda Updated podspec. 2018-09-25 02:44:40 -07:00
jonkykong 613fd9f68a Rest of previous commit. 2018-09-25 02:42:27 -07:00
jonkykong cb89d98dd8 Refactoring + Merge branch 'pr/399' into 5.0.0
* pr/399:
  feat: update swift version for all sub-projects (example,  pod, etc) to 4.2
  feat: update pod swift version to 4.2
  feat: update support for swift 4.2 (source and example)

# Conflicts:
#	Pod/Classes/SideMenuManager.swift
2018-09-25 02:39:36 -07:00
jonkykong 419eabb79d Merge branch 'pr/389' into 5.0.0
* pr/389:
  Parametrization of animation completion curve. Pod version 4.0.1

# Conflicts:
#	Pod/Classes/SideMenuManager.swift
2018-09-25 02:15:52 -07:00
jonkykong fee9c3cb20 Refactor. 2018-09-25 02:05:06 -07:00
Maxym Savisko cc436ded70 feat: update swift version for all sub-projects (example, pod, etc) to 4.2 2018-09-18 17:29:54 +03:00
Maxym Savisko aeaeba35ac feat: update pod swift version to 4.2 2018-09-18 17:20:32 +03:00
Maxym Savisko 51576e149d feat: update support for swift 4.2 (source and example) 2018-09-18 17:19:31 +03:00
AnatoliyPozdeyev 5f27a26c13 Parametrization of animation completion curve.
Pod version 4.0.1
2018-08-17 15:17:19 +03:00
Olcay Ertaş 0ff87874f6 Update SideMenuManager.swift
Static declarations are implicitly 'final'; use 'public' instead of 'open'
2018-08-14 10:31:27 +03:00
Jon Kent 83f8e461e1 Update README.md 2018-05-23 18:50:57 -07:00
jonkykong 40e8408ce1 Update README for Github. 2018-05-23 18:46:25 -07:00
jonkykong f66a3068b6 Merge tag '4.0.0'
* tag '4.0.0':
  Updated README and podspec.
  minor change to be compliant with swift 4.1
2018-05-23 18:45:48 -07:00
jonkykong 40ba7f335a Updated README and podspec. 2018-05-23 18:40:15 -07:00
jonkykong 32e6097602 Merge branch 'pr/345' into 4.0.0
* pr/345:
  minor change to be compliant with swift 4.1
2018-05-23 18:36:28 -07:00
jonkykong 2820b58e78 Merge tag '3.1.7'
* tag '3.1.7':
  Refactor.
  Refactor.
  Updated example storyboard.
  Upped minimum deployment target.
  Refactor.
  optimize check
  add nil check
  Fixed func hideMenuStart() to avoid problems when mainViewController is released at hideMenuComplete() func
2018-05-23 18:36:00 -07:00
jonkykong 5f0ecdb410 Merge branch 'pr/320' into 3.1.7
* pr/320:
  Refactor.
  optimize check
  add nil check
2018-05-23 18:08:09 -07:00
jonkykong b58e5c0e63 Refactor. 2018-05-23 18:07:55 -07:00
jonkykong 4319029d98 Merge branch 'pr/311' into 3.1.7
* pr/311:
  Refactor.
  Fixed func hideMenuStart() to avoid problems when mainViewController is released at hideMenuComplete() func

# Conflicts:
#	Pod/Classes/SideMenuTransition.swift
2018-05-23 18:03:44 -07:00
jonkykong 4b8f65812f Refactor. 2018-05-23 18:02:33 -07:00
jonkykong 86a40d1346 Updated example storyboard. 2018-05-23 17:31:34 -07:00
jonkykong 4e896375f2 Upped minimum deployment target. 2018-05-23 17:05:52 -07:00
jonkykong 6c5469c40c Refactor. 2018-05-21 19:13:55 -07:00
Iosif Moldovan 965531907b minor change to be compliant with swift 4.1 2018-04-03 13:15:50 +03:00
jonkykong 1b6b8c446c Fix for exit gesture cancelling menu taps. 2018-02-20 02:38:33 -08:00
Peter Kreinz bcf178c3d5 optimize check 2018-02-05 10:38:38 +01:00
Peter Kreinz 46b4bdc376 add nil check 2018-01-29 17:50:08 +01:00
Jon Kent 175042e238 Update README.md 2018-01-26 11:06:54 -08:00
Jon Kent 2a4d78b7fa Update README.md 2018-01-26 11:05:26 -08:00
Alex Zaragoza 1df40fa25c Fixed func hideMenuStart() to avoid problems when mainViewController is released at hideMenuComplete() func 2018-01-15 14:00:52 +01:00
Jon Kent 8573045525 Update README.md 2018-01-09 02:23:18 -08:00
Jon Kent 9e5b11c1cc Update README.md 2017-12-20 10:00:40 -08:00
Jon Kent ecdbfbb11a Update README.md 2017-12-05 15:44:21 -08:00
Jon Kent 5dc207396f Update README.md 2017-11-21 14:29:57 -08:00
Jon Kent 67886c73a8 Update README.md 2017-11-21 14:29:18 -08:00
jonkykong cbc1ac6624 Update README for Github. 2017-11-21 13:20:38 -08:00
jonkykong 9c7111e7e3 Merge tag '3.1.5'
* tag '3.1.5':
  Updated README requirements.
  Updated README for Cocoapods.
  Exposed defaultManager for Objective-C support.
  Updated podspec.
  Additional changes for objective-C support in UISideMenuNavigationController
  fix objc inference in swift 4
2017-11-21 13:19:21 -08:00
jonkykong df48679df4 Updated README requirements. 2017-11-21 13:15:29 -08:00
jonkykong f32cf72443 Updated README for Cocoapods. 2017-11-21 13:10:30 -08:00
jonkykong b15180fb8a Exposed defaultManager for Objective-C support. 2017-11-21 13:06:57 -08:00
jonkykong 6eae7987ef Updated podspec. 2017-11-21 13:05:03 -08:00
jonkykong c6b7780daf Additional changes for objective-C support in UISideMenuNavigationController 2017-11-21 13:04:52 -08:00
herrernst c54f364d49 fix objc inference in swift 4
in swift 4, swift subclasses of objective-c classes don't export members by default, see https://help.apple.com/xcode/mac/current/#/deve838b19a1
2017-11-07 12:27:45 +01:00
jonkykong 5ac61bc981 Revert README for Cocoapods. 2017-10-31 00:31:17 -07:00
jonkykong b647880794 Merge tag '3.1.4'
* tag '3.1.4':
  Update README for Cocoapods.
  Updated podspec.
  Fixed SideMenu.UISideMenuNavigationController crash on init(nibName:bundle:)
2017-10-31 00:30:51 -07:00
jonkykong 2e684440fc Update README for Cocoapods. 2017-10-31 00:28:19 -07:00
jonkykong 6064d6d5fc Updated podspec. 2017-10-31 00:27:58 -07:00
Lawrence Gimenez d13ed0ea9b Fixed SideMenu.UISideMenuNavigationController crash on init(nibName:bundle:) 2017-10-31 15:06:59 +08:00
jonkykong ef607b3ab2 Update README for Github. 2017-10-28 12:05:27 -07:00
jonkykong 069b974145 Merge tag '3.1.3'
* tag '3.1.3':
  Update README for cocoapods.
  Updated podspec.
  Updated README.
2017-10-28 12:04:53 -07:00
jonkykong 3e452b2a69 Update README for cocoapods. 2017-10-28 11:58:48 -07:00
jonkykong 021fe8cd6a Merge branch 'master' into 3.1.3
* master:
  Exposed delegate to @objc.
  Adding omitted initializer.
  README corrections.
2017-10-28 11:58:01 -07:00
jonkykong fd6ecbbece Updated podspec. 2017-10-28 11:55:43 -07:00
jonkykong 313cda5d69 Updated README. 2017-10-28 11:55:24 -07:00
jonkykong e35a46b075 Exposed delegate to @objc. 2017-10-28 11:52:58 -07:00
jonkykong 3702ecb770 Adding omitted initializer. 2017-10-28 11:52:23 -07:00
jonkykong 893818b582 README corrections. 2017-10-26 18:48:29 -07:00
jonkykong f21ed8965d Revert README for Github. 2017-10-26 18:40:22 -07:00
jonkykong db1cf2a6b6 Merge tag '3.1.2'
* tag '3.1.2':
  Updated podspec.
  Updated README.
  Allow for specifying the sideMenuDelegate, otherwise it discovers it automatically.
  Last commit was incorrect -- but this commit fixes it and includes a work-around for more experience devs who may still want to use default initializer as well as silence some newbie warnings.
  Override of navigation controller default init to prevent new developers from seeing black menus.
  It should be possible now to have the menu slide out even if pushing the new view is not animated itself (animating both can look a bit weird when relying on 'animated' only)
2017-10-26 18:39:49 -07:00
jonkykong a66367d84a Updated podspec. 2017-10-26 18:10:58 -07:00
jonkykong 5f8bdab1dc Updated README. 2017-10-26 18:10:23 -07:00
jonkykong 86f592a20d Support for forcing animated menu dismissal even when pushed view controllers are not animated. 2017-10-26 18:08:43 -07:00
jonkykong dd0a14fa61 Allow for specifying the sideMenuDelegate, otherwise it discovers it automatically. 2017-10-26 17:07:46 -07:00
jonkykong 2ba0ef7453 Last commit was incorrect -- but this commit fixes it and includes a work-around for more experience devs who may still want to use default initializer as well as silence some newbie warnings. 2017-10-24 12:15:41 -07:00
jonkykong 6f57e37129 Override of navigation controller default init to prevent new developers from seeing black menus. 2017-10-24 12:13:06 -07:00
Andreas Hilbert 2af0d86c97 It should be possible now to have the menu slide out even if pushing the new view is not animated itself (animating both can look a bit weird when relying on 'animated' only) 2017-10-19 12:11:20 +02:00
Jon Kent 3dc08de6ec Update README.md 2017-10-17 20:03:10 -07:00
Jon Kent 646f2a8094 Update README.md 2017-10-16 23:18:59 -07:00
Jon Kent ef867ff2b3 Update README.md 2017-10-16 23:18:26 -07:00
jonkykong 49dd185fa7 Updated README for Github. 2017-10-11 14:45:34 -07:00
jonkykong 6a87536f76 Merge tag '3.1.1'
* tag '3.1.1':
  Updated podspec.
  Update README for Cocoapods.
  README correction.
  Better logic for managing UISideMenuNavigationController properties across interface builder and programmatic instantiations.
2017-10-11 14:45:10 -07:00
jonkykong a2f299bb5f Updated podspec. 2017-10-11 14:43:08 -07:00
jonkykong 031f97d770 Update README for Cocoapods. 2017-10-11 14:40:45 -07:00
jonkykong 977f9a5b70 README correction. 2017-10-11 14:39:34 -07:00
jonkykong 3a14516905 Better logic for managing UISideMenuNavigationController properties across interface builder and programmatic instantiations. 2017-10-11 14:39:22 -07:00
jonkykong ddefba9c87 Revert README for Github. 2017-10-10 18:37:00 -07:00
jonkykong d3f59a45a7 Merge tag '3.1'
* tag '3.1':
  Updated README for Cocoapods.
  Updated podspec.
  Update README.md
  Updated README.
  Fix for non-animated dismissal of menu causing a black screen.
  Renamed class and refactored how blurring works in UITableViewVibrantCell.
  Major project update to support multiple SideMenuManager instances beyond the primary instance, if necessary.
  Added isHidden property.
  Support for delegate methods on SideMenu appearing/disappearing.
  Refactor.
  Refactoring.
  Fix for menuDismissOnPush as it was incorrectly applied.
  Fix for regression on enums to objective-C.
2017-10-10 18:36:29 -07:00
jonkykong 1d2f233e7f Updated README for Cocoapods. 2017-10-10 18:33:31 -07:00
jonkykong 2a650bec7f no message 2017-10-10 18:31:05 -07:00
jonkykong a8cb38c798 Updated podspec. 2017-10-10 18:27:15 -07:00
Jon Kent b7386851df Update README.md 2017-10-10 18:26:53 -07:00
jonkykong 6e1cb822bf Updated README. 2017-10-10 17:37:13 -07:00
jonkykong 10197c53cf Fix for non-animated dismissal of menu causing a black screen. 2017-10-10 17:37:00 -07:00
jonkykong 90e252dc78 Renamed class and refactored how blurring works in UITableViewVibrantCell. 2017-10-10 17:36:29 -07:00
jonkykong 553cdeae98 Major project update to support multiple SideMenuManager instances beyond the primary instance, if necessary. 2017-10-10 17:24:07 -07:00
jonkykong 26b26c4862 Added isHidden property. 2017-10-06 16:56:40 -07:00
jonkykong 05f8012c66 Support for delegate methods on SideMenu appearing/disappearing. 2017-10-06 16:56:25 -07:00
jonkykong 45586dd398 Refactor. 2017-10-06 16:55:05 -07:00
jonkykong 92375186c8 Refactoring. 2017-10-06 16:52:57 -07:00
jonkykong c63f86feae Fix for menuDismissOnPush as it was incorrectly applied. 2017-10-06 16:51:39 -07:00
jonkykong 3e01179dec Fix for regression on enums to objective-C. 2017-10-06 16:43:01 -07:00
jonkykong 8a3ebd672e Revert README for Github. 2017-09-26 23:50:54 -07:00
jonkykong c6a04437b6 Merge tag '3.0.2'
* tag '3.0.2':
  Updated podspec and README for cocoapods.
  Corrected logic for default menu width.
2017-09-26 23:50:08 -07:00
jonkykong bf241ec554 Updated podspec and README for cocoapods. 2017-09-26 23:46:56 -07:00
jonkykong d867a67899 Corrected logic for default menu width. 2017-09-26 23:42:32 -07:00
Jon Kent 80213f5e88 Merge pull request #261 from jonkykong/add-code-of-conduct-1-1
Create CODE_OF_CONDUCT.md
2017-09-21 13:41:10 -07:00
Jon Kent 66cc6cad35 Create CODE_OF_CONDUCT.md 2017-09-21 13:40:46 -07:00
Jon Kent db97060777 Update README.md 2017-09-21 13:31:08 -07:00
Jon Kent 4d32054356 Update README.md 2017-09-21 04:49:43 -07:00
jonkykong 432dfe988f Updated README for Github. 2017-09-21 04:47:27 -07:00
jonkykong 1e8f091bb0 Merge tag '3.0.1'
* tag '3.0.1':
  Updated podspec.
  Fixed hack to more specific logic.
2017-09-21 04:41:45 -07:00
jonkykong f2df2e28d8 Updated podspec. 2017-09-21 04:41:11 -07:00
jonkykong b6a2466dec Fixed hack to more specific logic. 2017-09-21 04:40:42 -07:00
jonkykong 8bbe75d5c7 Merge tag '3.0.0'
* tag '3.0.0':
  Updated podspec.
  Additional Swift4 support updates.
  Fix for Swift 4 and version 2.3.4
2017-09-21 04:25:21 -07:00
jonkykong ad462962fd Updated podspec. 2017-09-21 04:23:19 -07:00
jonkykong 6ed444f433 Merge branch 'pr/253' into 3.0.0
* pr/253:
  Additional Swift4 support updates.
  Fix for Swift 4 and version 2.3.4
2017-09-21 04:12:50 -07:00
jonkykong a65e26cb47 Additional Swift4 support updates. 2017-09-21 02:59:40 -07:00
jonkykong 94610771b4 Merge tag '2.3.4'
* tag '2.3.4':
  Updated README and podspec.
  Added comment.
  Changed menuAnimationCompleteGestureDuration default.
  Changing individual menu width properties in favor of a property on UISideMenuNavigationController.
  Refactor.
  Formatting.
  Support for UISplitViewControllers when pushing view controllers.
  These methods will never be called as they are handled by the topViewController.
  Neglected to use menuDismissOnPush switch in code.
  Fixes to maintain iOS 11 animation smoothness.
  Refactor.
  Changed MainViewController's scrollview to align to the topLayoutGuide.
  Add missing designated initialiser to UITableViewVibrantCell
  Set right menu width equal half of left menu width in example
  Add supporting of different left and right menu width
2017-09-21 02:04:58 -07:00
jonkykong 5599796e9d Updated README and podspec. 2017-09-21 02:04:06 -07:00
jonkykong 33449c84a0 Merge branch 'pr/248' into 2.3.4
* pr/248:
  Added comment.
  Add missing designated initialiser to UITableViewVibrantCell
2017-09-21 01:53:02 -07:00
jonkykong 458b246013 Added comment. 2017-09-21 01:52:44 -07:00
jonkykong a58a170979 Changed menuAnimationCompleteGestureDuration default. 2017-09-21 01:35:46 -07:00
jonkykong e4c43569de Merge branch 'pr/228' into 2.3.4
* pr/228:
  Changing individual menu width properties in favor of a property on UISideMenuNavigationController.
  Set right menu width equal half of left menu width in example
  Add supporting of different left and right menu width

# Conflicts:
#	Pod/Classes/SideMenuTransition.swift
2017-09-21 01:34:34 -07:00
jonkykong 966e1c9976 Changing individual menu width properties in favor of a property on UISideMenuNavigationController. 2017-09-21 01:30:58 -07:00
jonkykong 1241215e53 Refactor. 2017-09-20 23:25:19 -07:00
jonkykong 09070849d8 Formatting. 2017-09-20 22:54:04 -07:00
jonkykong 8705078fa5 Support for UISplitViewControllers when pushing view controllers. 2017-09-20 22:51:40 -07:00
jonkykong 48a39b4573 These methods will never be called as they are handled by the topViewController. 2017-09-20 22:50:23 -07:00
jonkykong 3611a6f5b8 Neglected to use menuDismissOnPush switch in code. 2017-09-20 22:49:30 -07:00
jonkykong 701d482714 Fixes to maintain iOS 11 animation smoothness. 2017-09-20 22:48:39 -07:00
jonkykong 9574c37479 Refactor. 2017-09-20 22:48:14 -07:00
jonkykong 52faf9a7e1 Changed MainViewController's scrollview to align to the topLayoutGuide. 2017-09-20 22:47:56 -07:00
Ranjithkumar Matheswaran 05a3659255 Fix for Swift 4 and version 2.3.4 2017-08-31 18:30:48 +05:30
Mark Woollard ef0c5fceed Add missing designated initialiser to UITableViewVibrantCell
So cell can be registered with UITableView without subclassing for simple use cases. Without this initialiser dequeuing instance of the cell will cause a crash.
2017-08-18 10:36:38 +01:00
Alex Kozin eab7e274e8 Set right menu width equal half of left menu width in example 2017-07-20 18:16:59 +07:00
Alex Kozin f9ec208e36 Add supporting of different left and right menu width 2017-07-20 18:16:01 +07:00
Jon Kent 6b9607fc9a Update README.md 2017-07-02 12:33:44 -07:00
jonkykong 8ad4b3a4d9 Revert README for Github. 2017-06-30 16:56:34 -07:00
jonkykong b0357d3f54 Merge tag '2.3.3'
* tag '2.3.3':
  Updated podspec and README.
  Added menuDismissOnPush property.
  Fix for single menu setups losing ability to swipe menu if wrong side is swiped.
2017-06-30 16:51:36 -07:00
jonkykong 7a30c5441e Updated podspec and README. 2017-06-30 16:50:04 -07:00
jonkykong 13e3d504f1 Added menuDismissOnPush property. 2017-06-30 16:48:19 -07:00
jonkykong 02578a894a Fix for single menu setups losing ability to swipe menu if wrong side is swiped. 2017-06-30 16:45:15 -07:00
Jon Kent 2e54a9d21a Create ISSUE_TEMPLATE.md 2017-06-08 01:45:53 -07:00
jonkykong d31f4419e1 Merge tag '2.3.2'
* tag '2.3.2':
  README edit.
  Updated podspec and README for cocoa pods.

Updated README for Github.
2017-04-26 12:44:34 -07:00
jonkykong 7bf1668184 README edit. 2017-04-26 12:38:24 -07:00
jonkykong e12faa68c9 Updated podspec and README for cocoa pods. 2017-04-26 12:37:10 -07:00
jonkykong ecebaca9b9 Logic correction. 2017-04-26 12:21:58 -07:00
jonkykong aeb660b02f Fix for menu not restoring when background on iPad in iOS 10. 2017-04-26 12:21:45 -07:00
jonkykong e6eb28385c Merge tag '2.3.1'
* tag '2.3.1':
  Updated pod spec and README for Cocoapods.
  Updated project settings.
  Reverting old logic that kept the layout correct when presenting a sub-screen.
  Subtle tweak if a larger transform is used on the main view controller when menu is presented (edge case).
  Fix for disabling gestures. Gestures were being added multiple times preventing all of them from being disabled when the menuEnableSwipeGestures was used.
2017-04-11 03:48:47 -07:00
jonkykong f9f8fd7817 Updated pod spec and README for Cocoapods. 2017-04-11 03:44:32 -07:00
jonkykong dda720eee7 Updated project settings. 2017-04-11 03:41:51 -07:00
jonkykong 8bb2505b6f Reverting old logic that kept the layout correct when presenting a sub-screen. 2017-04-11 03:41:13 -07:00
jonkykong 2878eea03f Subtle tweak if a larger transform is used on the main view controller when menu is presented (edge case). 2017-04-11 03:40:28 -07:00
jonkykong 7512cb9373 Fix for disabling gestures. Gestures were being added multiple times preventing all of them from being disabled when the menuEnableSwipeGestures was used. 2017-04-11 03:35:54 -07:00
Jon Kent 189586d8e8 Update CONTRIBUTING.md 2017-04-04 01:06:08 -07:00
Jon Kent f4d78af501 Update README.md 2017-03-28 11:57:24 -07:00
Jon Kent af2ef21f88 Update README.md 2017-03-26 13:36:39 -07:00
Jon Kent 25b87e4780 Update README.md 2017-03-07 12:23:00 -08:00
jonkykong c966675305 Revert README for Github. 2017-03-06 02:55:15 -08:00
jonkykong b0dfba206c Merge tag '2.3.0'
* tag '2.3.0':
  Updated README and podspec.
  Fix for tapView to not be sized to main screen which may be transformed and therefor hard to touch.
  Support for in-call status bar height change.
  Refactoring.
  Updated demo project to show various SideMenu events.
  Logic simplification.
  Removal of no longer needed logic.
  Updated comments and minor refactor.
  Fix for keyboard animations being confused during SideMenu display.
  Updated documentation.
  Fix deprecation warnings in swift 3.1
2017-03-06 02:54:35 -08:00
87 changed files with 5033 additions and 2788 deletions
+39
View File
@@ -0,0 +1,39 @@
# iOS CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/ios-migrating-from-1-2/ for more details
#
version: 2
jobs:
build:
# Specify the Xcode version to use
macos:
xcode: "10.3.0"
steps:
- checkout
# Install CocoaPods
- run:
name: Install CocoaPods
command: pod install
# Build the app and run tests
- run:
name: Build and run tests
command: fastlane scan
environment:
SCAN_DEVICE: iPhone Xʀ
SCAN_SCHEME: SideMenu Example
# Collect XML test results data to show in the UI,
# and save the same XML files under test-results folder
# in the Artifacts tab
- store_test_results:
path: test_output/report.xml
- store_artifacts:
path: /tmp/test-results
destination: scan-test-results
- store_artifacts:
path: ~/Library/Logs/scan
destination: scan-logs
+2 -2
View File
@@ -4,7 +4,7 @@ Thank you for your interest in SideMenu!
I have received a surprising amount of questions about SideMenu since putting it up here. A few people in the community have identified some problems and helped contribute to SideMenu to make it better for everyone and I'm truly grateful for the support! Keep them coming!
I have also received a number of questions about people having issues implementing SideMenu, mostly from beginners learning how to code. As much as I would love to help all of you, I simply do **not** have the time to teach you. I am only supporting bugfixes or reviewing pull requests.
I have also received a number of questions about people having issues implementing SideMenu, mostly from beginners learning how to code. As much as I would love to help all of you, **I do not have time to teach you**. I am only supporting bugfixes or reviewing pull requests.
I spent a lot of time putting together a detailed [README](https://github.com/jonkykong/SideMenu/blob/master/README.md), adding comments about usage in code, and provided a [demo project](https://github.com/jonkykong/SideMenu/tree/master/Example). These will give you all the information you need to work through any problem, **saving _you_ the time it takes for me to personally respond.**
@@ -17,7 +17,7 @@ I spent a lot of time putting together a detailed [README](https://github.com/jo
### If your question is about SideMenu not working the way it's described in the [README](https://github.com/jonkykong/SideMenu/blob/master/README.md)...
- This *may* be a bug. You must be able to reproduce the bug in the [demo project](https://github.com/jonkykong/SideMenu/tree/master/Example) which has a minimal amount of code. This helps ensure you don't have a bug in your code unrelated to SideMenu. If the bug is reproducable, open an issue and I will respond to it when I find time.
**Again**, please do **not** email me or open any issues if you want to know how to use SideMenu or are having trouble getting it to do behave a specific way not described in the [README](https://github.com/jonkykong/SideMenu/blob/master/README.md). I am not **tech support**. I am not a **teacher**. If you open an issue while failing to follow these guidelines or use the provided templates your **request for help will be ignored**.
**Again**, please do **not** email me or open any issues if you want to know how to use SideMenu or are having trouble getting it to behave a specific way not described in the [README](https://github.com/jonkykong/SideMenu/blob/master/README.md). I am not **tech support**. I am not a **teacher**. If you open an issue while failing to follow these guidelines or use the provided templates your **request for help will be ignored**.
### Thanks again for your support and for being respectful of my time.
I apologize if this seems harsh, but there have been too many developers that have willfully ignored all of this and continued to contact me.
+2
View File
@@ -0,0 +1,2 @@
github: [jonkykong]
custom: ["https://www.paypal.me/jonkykong"]
+1 -2
View File
@@ -1,5 +1,4 @@
<!--- Provide a general summary of your changes in the Title above -->
<!--- IF YOU DELETE OR IGNORE THIS TEMPLATE WHEN OPENING A NEW ISSUE, YOUR ISSUE WILL BE IGNORED -->
<!--- IF YOU DELETE OR IGNORE THIS TEMPLATE YOUR ISSUE WILL BE IGNORED AND CLOSED -->
## New Issue Checklist
<!--- Please complete all of the checks below before submitting a new issue (complete a check by marking it [x] with no spaces) -->
I have read the [guidelines for contributing](https://github.com/jonkykong/SideMenu/blob/master/.github/CONTRIBUTING.md) and I understand:
+34
View File
@@ -0,0 +1,34 @@
---
name: Bug Report
about: You must complete this template or your report will be automatically closed.
title: ''
labels: Bug - Help Wanted!
assignees: ''
---
**I have read the [guidelines for contributing](https://github.com/jonkykong/SideMenu/blob/master/.github/CONTRIBUTING.md) and I understand**
- [ ] My issue is happening in the **latest version** of SideMenu (older versions are no longer maintained).
- [ ] My issue was **not** solved in the [README](https://github.com/jonkykong/SideMenu/blob/master/README.md).
- [ ] My issue can **not** be answered on [stackoverflow.com](stackoverflow.com).
- [ ] My issue is **not** a request for new functionality that I am unwilling to build and contribute with a pull request.
- [ ] My issue **is** reproducible in the [demo project](https://github.com/jonkykong/SideMenu/tree/master/Example).
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
+16
View File
@@ -0,0 +1,16 @@
---
name: Feature Request
about: Suggest an idea for this project.
title: ''
labels: Feature Request - Help Wanted!
assignees: ''
---
SideMenu currently meets the majority of people's needs with the features it already has. However, this is a great opportunity for you to [join the proud members](https://github.com/jonkykong/SideMenu/graphs/contributors) who have contributed to this open source project! Feel free to open an issue to ask any clarifying questions for your new feature before you start building. Open a [pull request](https://github.com/jonkykong/SideMenu/pull/new/master) when you're ready for me to merge it.
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Ask any questions you have related to developing your solution**
A clear and concise set of questions you'd like to ask.
-1
View File
@@ -1 +0,0 @@
3.0
+46
View File
@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at yo@massappeal.co. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
-54
View File
@@ -1,54 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2016 Jon Kent. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
<rect key="frame" x="20" y="626.5" width="335" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SideMenu" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
<rect key="frame" x="20" y="202" width="335" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="centerX" secondItem="obG-Y5-kRd" secondAttribute="centerX" id="5cz-MP-9tL"/>
<constraint firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
<constraint firstItem="obG-Y5-kRd" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" constant="20" symbolic="YES" id="SfN-ll-jLj"/>
<constraint firstAttribute="bottom" secondItem="obG-Y5-kRd" secondAttribute="bottom" constant="20" id="Y44-ml-fuU"/>
<constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
<constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" constant="20" symbolic="YES" id="x7j-FC-K8j"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
-92
View File
@@ -1,92 +0,0 @@
//
// MainViewController.swift
//
// Created by Jon Kent on 11/12/15.
// Copyright © 2015 Jon Kent. All rights reserved.
//
import SideMenu
class MainViewController: UIViewController {
@IBOutlet fileprivate weak var presentModeSegmentedControl:UISegmentedControl!
@IBOutlet fileprivate weak var blurSegmentControl:UISegmentedControl!
@IBOutlet fileprivate weak var darknessSlider:UISlider!
@IBOutlet fileprivate weak var shadowOpacitySlider:UISlider!
@IBOutlet fileprivate weak var screenWidthSlider:UISlider!
@IBOutlet fileprivate weak var shrinkFactorSlider:UISlider!
@IBOutlet fileprivate weak var blackOutStatusBar:UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
setupSideMenu()
setDefaults()
}
fileprivate func setupSideMenu() {
// Define the menus
SideMenuManager.menuLeftNavigationController = storyboard!.instantiateViewController(withIdentifier: "LeftMenuNavigationController") as? UISideMenuNavigationController
SideMenuManager.menuRightNavigationController = storyboard!.instantiateViewController(withIdentifier: "RightMenuNavigationController") as? UISideMenuNavigationController
// Enable gestures. The left and/or right menus must be set up above for these to work.
// Note that these continue to work on the Navigation Controller independent of the View Controller it displays!
SideMenuManager.menuAddPanGestureToPresent(toView: self.navigationController!.navigationBar)
SideMenuManager.menuAddScreenEdgePanGesturesToPresent(toView: self.navigationController!.view)
// Set up a cool background image for demo purposes
SideMenuManager.menuAnimationBackgroundColor = UIColor(patternImage: UIImage(named: "background")!)
}
fileprivate func setDefaults() {
let modes:[SideMenuManager.MenuPresentMode] = [.menuSlideIn, .viewSlideOut, .menuDissolveIn]
presentModeSegmentedControl.selectedSegmentIndex = modes.index(of: SideMenuManager.menuPresentMode)!
let styles:[UIBlurEffectStyle] = [.dark, .light, .extraLight]
if let menuBlurEffectStyle = SideMenuManager.menuBlurEffectStyle {
blurSegmentControl.selectedSegmentIndex = styles.index(of: menuBlurEffectStyle) ?? 0
} else {
blurSegmentControl.selectedSegmentIndex = 0
}
darknessSlider.value = Float(SideMenuManager.menuAnimationFadeStrength)
shadowOpacitySlider.value = Float(SideMenuManager.menuShadowOpacity)
shrinkFactorSlider.value = Float(SideMenuManager.menuAnimationTransformScaleFactor)
screenWidthSlider.value = Float(SideMenuManager.menuWidth / view.frame.width)
blackOutStatusBar.isOn = SideMenuManager.menuFadeStatusBar
}
@IBAction fileprivate func changeSegment(_ segmentControl: UISegmentedControl) {
switch segmentControl {
case presentModeSegmentedControl:
let modes:[SideMenuManager.MenuPresentMode] = [.menuSlideIn, .viewSlideOut, .viewSlideInOut, .menuDissolveIn]
SideMenuManager.menuPresentMode = modes[segmentControl.selectedSegmentIndex]
case blurSegmentControl:
if segmentControl.selectedSegmentIndex == 0 {
SideMenuManager.menuBlurEffectStyle = nil
} else {
let styles:[UIBlurEffectStyle] = [.dark, .light, .extraLight]
SideMenuManager.menuBlurEffectStyle = styles[segmentControl.selectedSegmentIndex - 1]
}
default: break;
}
}
@IBAction fileprivate func changeSlider(_ slider: UISlider) {
switch slider {
case darknessSlider:
SideMenuManager.menuAnimationFadeStrength = CGFloat(slider.value)
case shadowOpacitySlider:
SideMenuManager.menuShadowOpacity = slider.value
case shrinkFactorSlider:
SideMenuManager.menuAnimationTransformScaleFactor = CGFloat(slider.value)
case screenWidthSlider:
SideMenuManager.menuWidth = view.frame.width * CGFloat(slider.value)
default: break;
}
}
@IBAction fileprivate func changeSwitch(_ switchControl: UISwitch) {
SideMenuManager.menuFadeStatusBar = switchControl.isOn
}
}
-49
View File
@@ -1,49 +0,0 @@
//
// SideMenuTableView.swift
// SideMenu
//
// Created by Jon Kent on 4/5/16.
// Copyright © 2016 CocoaPods. All rights reserved.
//
import Foundation
import SideMenu
class SideMenuTableView: UITableViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// this will be non-nil if a blur effect is applied
guard tableView.backgroundView == nil else {
return
}
// Set up a cool background image for demo purposes
let imageView = UIImageView(image: UIImage(named: "saturn"))
imageView.contentMode = .scaleAspectFit
imageView.backgroundColor = UIColor.black.withAlphaComponent(0.2)
tableView.backgroundView = imageView
print("SideMenu Appearing!")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("SideMenu Appeared!")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("SideMenu Disappearing!")
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
print("SideMenu Disappeared!")
}
}
-29
View File
@@ -1,29 +0,0 @@
import UIKit
import XCTest
import SideMenu
class Tests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
XCTAssert(true, "Pass")
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure() {
// Put the code you want to measure the time of here.
}
}
}
+17
View File
@@ -0,0 +1,17 @@
// swift-tools-version:5.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "SideMenu",
products: [
.library(name: "SideMenu", targets: ["SideMenu"])
],
dependencies: [],
targets: [
.target(name: "SideMenu", path: "Pod/Classes")
],
swiftLanguageVersions: [.v4_2, .v5]
)
+216
View File
@@ -0,0 +1,216 @@
//
// Deprecations.swift
// SideMenu
//
// Created by Jon Kent on 7/3/19.
//
import UIKit
// Deprecations; to be removed at a future date.
extension SideMenuManager {
@available(*, deprecated, renamed: "leftMenuNavigationController")
open var menuLeftNavigationController: SideMenuNavigationController? {
get { return nil }
set {}
}
@available(*, deprecated, renamed: "rightMenuNavigationController")
open var menuRightNavigationController: SideMenuNavigationController? {
get { return nil }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuPresentMode: SideMenuPresentationStyle {
get { return .viewSlideOut }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuPushStyle: SideMenuPushStyle {
get { return .default }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuAllowPushOfSameClassTwice: Bool {
get { return true }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuWidth: CGFloat {
get { return 0 }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuAnimationPresentDuration: Double {
get { return 0.35 }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuAnimationDismissDuration: Double {
get { return 0.35 }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuAnimationCompleteGestureDuration: Double {
get { return 0.35 }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuPresentationStyle class.")
public var menuAnimationFadeStrength: CGFloat {
get { return 0 }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuPresentationStyle class.")
public var menuAnimationTransformScaleFactor: CGFloat {
get { return 1 }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuPresentationStyle class.")
public var menuAnimationBackgroundColor: UIColor? {
get { return nil }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuPresentationStyle class.")
public var menuShadowOpacity: Float {
get { return 0.5 }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuPresentationStyle class.")
public var menuShadowColor: UIColor {
get { return .black }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuPresentationStyle class.")
public var menuShadowRadius: CGFloat {
get { return 5 }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuPresentingViewControllerUserInteractionEnabled: Bool {
get { return false }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuPresentationStyle class.")
public var menuParallaxStrength: Int {
get { return 0 }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuFadeStatusBar: Bool {
get { return true }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuAnimationOptions: UIView.AnimationOptions {
get { return .curveEaseInOut }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuAnimationCompletionCurve: UIView.AnimationCurve {
get { return .easeIn }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuAnimationUsingSpringWithDamping: CGFloat {
get { return 1 }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuAnimationInitialSpringVelocity: CGFloat {
get { return 1 }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuDismissOnPush: Bool {
get { return true }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuAlwaysAnimate: Bool {
get { return false }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuDismissWhenBackgrounded: Bool {
get { return true }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuBlurEffectStyle: UIBlurEffect.Style? {
get { return nil }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public weak var menuLeftSwipeToDismissGesture: UIPanGestureRecognizer? {
get { return nil }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public weak var menuRightSwipeToDismissGesture: UIPanGestureRecognizer? {
get { return nil }
set {}
}
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuEnableSwipeGestures: Bool {
get { return true }
set {}
}
@available(*, deprecated, renamed: "enableSwipeToDismissGesture")
public var enableSwipeGestures: Bool {
get { return true }
set {}
}
@available(*, deprecated, renamed: "SideMenuPresentationStyle")
public typealias MenuPresentMode = SideMenuPresentationStyle
@available(*, deprecated, renamed: "addScreenEdgePanGesturesToPresent")
@discardableResult public func menuAddScreenEdgePanGesturesToPresent(toView view: UIView, forMenu sides: [PresentDirection] = [.left, .right]) -> [UIScreenEdgePanGestureRecognizer] {
return []
}
@available(*, deprecated, renamed: "addPanGestureToPresent")
@discardableResult public func menuAddPanGestureToPresent(toView view: UIView) -> UIPanGestureRecognizer {
return UIPanGestureRecognizer()
}
}
extension SideMenuPresentationStyle {
@available(*, deprecated, renamed: "viewSlideOutMenuIn")
public static var viewSlideInOut: SideMenuPresentationStyle { return viewSlideOutMenuIn }
}
@available(*, deprecated, renamed: "SideMenuNavigationController")
public typealias UISideMenuNavigationController = SideMenuNavigationController
@available(*, deprecated, renamed: "SideMenuNavigationControllerDelegate")
public typealias UISideMenuNavigationControllerDelegate = SideMenuNavigationControllerDelegate
+116
View File
@@ -0,0 +1,116 @@
//
// Extensions.swift
// Pods-Example
//
// Created by Jon Kent on 7/1/19.
//
import UIKit
extension NSObject: InitializableClass {}
internal extension UIView {
@discardableResult func untransformed(_ block: () -> CGFloat) -> CGFloat {
let t = transform
transform = .identity
let value = block()
transform = t
return value
}
func bringToFront() {
superview?.bringSubviewToFront(self)
}
func untransform(_ block: () -> Void) {
untransformed { () -> CGFloat in
block()
return 0
}
}
static func animationsEnabled(_ enabled: Bool = true, _ block: () -> Void) {
let a = areAnimationsEnabled
setAnimationsEnabled(enabled)
block()
setAnimationsEnabled(a)
}
}
internal extension UIViewController {
// View controller actively displayed in that layer. It may not be visible if it's presenting another view controller.
var activeViewController: UIViewController {
switch self {
case let navigationController as UINavigationController:
return navigationController.topViewController?.activeViewController ?? self
case let tabBarController as UITabBarController:
return tabBarController.selectedViewController?.activeViewController ?? self
case let splitViewController as UISplitViewController:
return splitViewController.viewControllers.last?.activeViewController ?? self
default:
return self
}
}
// View controller being displayed on screen to the user.
var topMostViewController: UIViewController {
let activeViewController = self.activeViewController
return activeViewController.presentedViewController?.topMostViewController ?? activeViewController
}
var containerViewController: UIViewController {
return navigationController?.containerViewController ??
tabBarController?.containerViewController ??
splitViewController?.containerViewController ??
self
}
@objc var isHidden: Bool {
return presentingViewController == nil
}
}
internal extension UIGestureRecognizer {
convenience init(addTo view: UIView, target: Any, action: Selector) {
self.init(target: target, action: action)
view.addGestureRecognizer(self)
}
convenience init?(addTo view: UIView?, target: Any, action: Selector) {
guard let view = view else { return nil }
self.init(addTo: view, target: target, action: action)
}
func remove() {
view?.removeGestureRecognizer(self)
}
}
internal extension UIPanGestureRecognizer {
var canSwitch: Bool {
return !(self is UIScreenEdgePanGestureRecognizer)
}
var xTranslation: CGFloat {
return view?.untransformed {
return self.translation(in: view).x
} ?? 0
}
var xVelocity: CGFloat {
return view?.untransformed {
return self.velocity(in: view).x
} ?? 0
}
}
internal extension UIApplication {
var keyWindow: UIWindow? {
return UIApplication.shared.windows.filter { $0.isKeyWindow }.first
}
}
+40
View File
@@ -0,0 +1,40 @@
//
// Initializable.swift
// SideMenu
//
// Created by Jon Kent on 7/2/19.
//
import Foundation
internal protocol InitializableClass: class {
init()
}
extension InitializableClass {
init(_ block: (Self) -> Void) {
self.init()
block(self)
}
@discardableResult func with(_ block: (Self) -> Void) -> Self {
block(self)
return self
}
}
public protocol InitializableStruct {
init()
}
public extension InitializableStruct {
init(_ block: (inout Self) -> Void) {
self.init()
block(&self)
}
@discardableResult mutating func with(_ block: (inout Self) -> Void) -> Self {
block(&self)
return self
}
}
+51
View File
@@ -0,0 +1,51 @@
//
// Print.swift
// SideMenu
//
// Created by Jon Kent on 12/5/18.
//
import Foundation
internal enum Print: String { case
cannotPush = "Attempt to push a View Controller from %@ where its navigationController == nil. It must be embedded in a UINavigationController for this to work.",
emptyMenu = "The menu doesn't have a view controller to show! SideMenuNavigationController needs a view controller to display just like a UINavigationController.",
menuAlreadyAssigned = "%@ was already assigned to the %@ of %@. When using multiple SideMenuManagers you may want to use new instances of SideMenuNavigationController instead of existing instances to avoid crashes if the menu is presented more than once.",
menuInUse = "%@ cannot be modified while it's presented.",
panGestureAdded = "%@ was called before %@ or %@ was set. Gestures will not work without a menu.",
property = "A menu's %@ property can only be changed when it is hidden.",
screenGestureAdded = "%@ was called before %@ was set. The gesture will not work without a menu. Use %@ to add gestures for only one menu.",
transitioningDelegate = "SideMenu requires use of the transitioningDelegate. It cannot be modified."
enum PropertyName: String { case
leftSide
}
static func warning(_ print: Print, arguments: CVarArg..., required: Bool = false) {
warning(String(format: print.rawValue, arguments: arguments), required: required)
}
static func warning(_ print: Print, arguments: PropertyName..., required: Bool = false) {
warning(String(format: print.rawValue, arguments: arguments.map { $0.rawValue }), required: required)
}
static func warning(_ print: Print, required: Bool = false) {
warning(print.rawValue, required: required)
}
}
private extension Print {
static func warning(_ message: String, required: Bool = false) {
let message = "SideMenu Warning: \(message)"
if required {
print(message)
return
}
#if !STFU_SIDEMENU
print(message)
#endif
}
}
+26
View File
@@ -0,0 +1,26 @@
//
// Protected.swift
// SideMenu
//
// Created by Jon Kent on 2/9/19.
//
import Foundation
internal final class Protected<T: Equatable> {
typealias ConditionBlock = (_ oldValue: T, T) -> T
private var _value: T
private var condition: ConditionBlock
public var value: T {
get { return _value }
set { _value = condition(_value, newValue) }
}
init(_ value: T, when condition: @escaping ConditionBlock) {
self._value = value
self.condition = condition
}
}
@@ -0,0 +1,232 @@
//
// SideMenuAnimationController.swift
// SideMenu
//
// Created by Jon Kent on 10/24/18.
//
import UIKit
internal protocol AnimationModel {
/// The animation options when a menu is displayed. Ignored when displayed with a gesture.
var animationOptions: UIView.AnimationOptions { get }
/// Duration of the remaining animation when the menu is partially dismissed with gestures. Default is 0.35 seconds.
var completeGestureDuration: Double { get }
/// Duration of the animation when the menu is dismissed without gestures. Default is 0.35 seconds.
var dismissDuration: Double { get }
/// The animation initial spring velocity when a menu is displayed. Ignored when displayed with a gesture.
var initialSpringVelocity: CGFloat { get }
/// Duration of the animation when the menu is presented without gestures. Default is 0.35 seconds.
var presentDuration: Double { get }
/// The animation spring damping when a menu is displayed. Ignored when displayed with a gesture.
var usingSpringWithDamping: CGFloat { get }
}
internal protocol SideMenuAnimationControllerDelegate: class {
func sideMenuAnimationController(_ animationController: SideMenuAnimationController, didDismiss viewController: UIViewController)
func sideMenuAnimationController(_ animationController: SideMenuAnimationController, didPresent viewController: UIViewController)
}
internal final class SideMenuAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
typealias Model = AnimationModel & PresentationModel
private var config: Model
private weak var containerView: UIView?
private let leftSide: Bool
private weak var originalSuperview: UIView?
private var presentationController: SideMenuPresentationController?
private unowned var presentedViewController: UIViewController?
private unowned var presentingViewController: UIViewController?
weak var delegate: SideMenuAnimationControllerDelegate?
init(config: Model, leftSide: Bool, delegate: SideMenuAnimationControllerDelegate? = nil) {
self.config = config
self.leftSide = leftSide
self.delegate = delegate
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard
let presentedViewController = transitionContext.presentedViewController,
let presentingViewController = transitionContext.presentingViewController
else { return }
if transitionContext.isPresenting {
self.containerView = transitionContext.containerView
self.presentedViewController = presentedViewController
self.presentingViewController = presentingViewController
self.presentationController = SideMenuPresentationController(
config: config,
leftSide: leftSide,
presentedViewController: presentedViewController,
presentingViewController: presentingViewController,
containerView: transitionContext.containerView
)
}
transition(using: transitionContext)
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
guard let transitionContext = transitionContext else { return 0 }
return duration(presenting: transitionContext.isPresenting, interactive: transitionContext.isInteractive)
}
func animationEnded(_ transitionCompleted: Bool) {
guard let presentedViewController = presentedViewController else { return }
if presentedViewController.isHidden {
delegate?.sideMenuAnimationController(self, didDismiss: presentedViewController)
} else {
delegate?.sideMenuAnimationController(self, didPresent: presentedViewController)
}
}
func transition(presenting: Bool, animated: Bool = true, interactive: Bool = false, alongsideTransition: (() -> Void)? = nil, complete: Bool = true, completion: ((Bool) -> Void)? = nil) {
prepare(presenting: presenting)
transitionWillBegin(presenting: presenting)
transition(
presenting: presenting,
animated: animated,
interactive: interactive,
animations: { [weak self] in
guard let self = self else { return }
self.transition(presenting: presenting)
alongsideTransition?()
}, completion: { [weak self] _ in
guard let self = self else { return }
if complete {
self.transitionDidEnd(presenting: presenting, completed: true)
self.finish(presenting: presenting, completed: true)
}
completion?(true)
})
}
func layout() {
presentationController?.containerViewWillLayoutSubviews()
}
}
private extension SideMenuAnimationController {
func duration(presenting: Bool, interactive: Bool) -> Double {
if interactive { return config.completeGestureDuration }
return presenting ? config.presentDuration : config.dismissDuration
}
func prepare(presenting: Bool) {
guard
presenting,
let presentingViewController = presentingViewController,
let presentedViewController = presentedViewController
else { return }
originalSuperview = presentingViewController.view.superview
containerView?.addSubview(presentingViewController.view)
containerView?.addSubview(presentedViewController.view)
}
func transitionWillBegin(presenting: Bool) {
// prevent any other menu gestures from firing
containerView?.isUserInteractionEnabled = false
if presenting {
presentationController?.presentationTransitionWillBegin()
} else {
presentationController?.dismissalTransitionWillBegin()
}
}
func transition(presenting: Bool) {
if presenting {
presentationController?.presentationTransition()
} else {
presentationController?.dismissalTransition()
}
}
func transitionDidEnd(presenting: Bool, completed: Bool) {
if presenting {
presentationController?.presentationTransitionDidEnd(completed)
} else {
presentationController?.dismissalTransitionDidEnd(completed)
}
containerView?.isUserInteractionEnabled = true
}
func finish(presenting: Bool, completed: Bool) {
guard
presenting != completed,
let presentingViewController = self.presentingViewController
else { return }
presentedViewController?.view.removeFromSuperview()
originalSuperview?.addSubview(presentingViewController.view)
}
func transition(using transitionContext: UIViewControllerContextTransitioning) {
prepare(presenting: transitionContext.isPresenting)
transitionWillBegin(presenting: transitionContext.isPresenting)
transition(
presenting: transitionContext.isPresenting,
animated: transitionContext.isAnimated,
interactive: transitionContext.isInteractive,
animations: { [weak self] in
guard let self = self else { return }
self.transition(presenting: transitionContext.isPresenting)
}, completion: { [weak self] _ in
guard let self = self else { return }
let completed = !transitionContext.transitionWasCancelled
self.transitionDidEnd(presenting: transitionContext.isPresenting, completed: completed)
self.finish(presenting: transitionContext.isPresenting, completed: completed)
// Called last. This causes the transition container to be removed and animationEnded() to be called.
transitionContext.completeTransition(completed)
})
}
func transition(presenting: Bool, animated: Bool = true, interactive: Bool = false, animations: @escaping (() -> Void) = {}, completion: @escaping ((Bool) -> Void) = { _ in }) {
if !animated {
animations()
completion(true)
return
}
let duration = self.duration(presenting: presenting, interactive: interactive)
if interactive {
// IMPORTANT: The non-interactive animation block will not complete if adapted for interactive. The below animation block must be used!
UIView.animate(
withDuration: duration,
delay: duration, // HACK: If zero, the animation briefly flashes in iOS 11.
options: .curveLinear,
animations: animations,
completion: completion
)
return
}
UIView.animate(
withDuration: duration,
delay: 0,
usingSpringWithDamping: config.usingSpringWithDamping,
initialSpringVelocity: config.initialSpringVelocity,
options: config.animationOptions,
animations: animations,
completion: completion
)
}
}
private extension UIViewControllerContextTransitioning {
var isPresenting: Bool {
return viewController(forKey: .from)?.presentedViewController === viewController(forKey: .to)
}
var presentingViewController: UIViewController? {
return viewController(forKey: isPresenting ? .from : .to)
}
var presentedViewController: UIViewController? {
return viewController(forKey: isPresenting ? .to : .from)
}
}
@@ -0,0 +1,65 @@
//
// SideMenuInteractiveTransitionController.swift
// SideMenu
//
// Created by Jon Kent on 12/28/18.
//
import UIKit
internal final class SideMenuInteractionController: UIPercentDrivenInteractiveTransition {
enum State { case
update(progress: CGFloat),
finish,
cancel
}
private(set) var isCancelled: Bool = false
private(set) var isFinished: Bool = false
init(cancelWhenBackgrounded: Bool = true, completionCurve: UIView.AnimationCurve = .easeIn) {
super.init()
self.completionCurve = completionCurve
guard cancelWhenBackgrounded else { return }
NotificationCenter.default.addObserver(self, selector: #selector(handleNotification), name: UIApplication.didEnterBackgroundNotification, object: nil)
}
override func cancel() {
isCancelled = true
super.cancel()
}
override func finish() {
isFinished = true
super.finish()
}
override func update(_ percentComplete: CGFloat) {
guard !isCancelled && !isFinished else { return }
super.update(percentComplete)
}
func handle(state: State) {
switch state {
case .update(let progress):
update(progress)
case .finish:
finish()
case .cancel:
cancel()
}
}
}
private extension SideMenuInteractionController {
@objc func handleNotification(notification: NSNotification) {
switch notification.name {
case UIApplication.didEnterBackgroundNotification:
cancel()
default: break
}
}
}
+187 -329
View File
@@ -5,349 +5,101 @@
// Copyright © 2015 Jon Kent. All rights reserved.
//
/* Example usage:
// Define the menus
SideMenuManager.menuLeftNavigationController = storyboard!.instantiateViewController(withIdentifier: "LeftMenuNavigationController") as? UISideMenuNavigationController
SideMenuManager.menuRightNavigationController = storyboard!.instantiateViewController(withIdentifier: "RightMenuNavigationController") as? UISideMenuNavigationController
// Enable gestures. The left and/or right menus must be set up above for these to work.
// Note that these continue to work on the Navigation Controller independent of the View Controller it displays!
SideMenuManager.menuAddPanGestureToPresent(toView: self.navigationController!.navigationBar)
SideMenuManager.menuAddScreenEdgePanGesturesToPresent(toView: self.navigationController!.view)
*/
import UIKit
open class SideMenuManager : NSObject {
@objc public enum MenuPushStyle : Int {
case defaultBehavior,
popWhenPossible,
replace,
preserve,
preserveAndHideBackButton,
subMenu
}
@objc public enum MenuPresentMode : Int {
case menuSlideIn,
viewSlideOut,
viewSlideInOut,
menuDissolveIn
}
// Bounds which has been allocated for the app on the whole device screen
internal static var appScreenRect: CGRect {
let appWindowRect = UIApplication.shared.keyWindow?.bounds ?? UIWindow().bounds
return appWindowRect
@objcMembers
public class SideMenuManager: NSObject {
final private class SideMenuPanGestureRecognizer: UIPanGestureRecognizer {}
final private class SideMenuScreenEdgeGestureRecognizer: UIScreenEdgePanGestureRecognizer {}
@objc public enum PresentDirection: Int { case
left = 1,
right = 0
init(leftSide: Bool) {
self.init(rawValue: leftSide ? 1 : 0)!
}
var edge: UIRectEdge {
switch self {
case .left: return .left
case .right: return .right
}
}
var name: String {
switch self {
case .left: return "leftMenuNavigationController"
case .right: return "rightMenuNavigationController"
}
}
}
/**
The push style of the menu.
There are six modes in MenuPushStyle:
- defaultBehavior: The view controller is pushed onto the stack.
- popWhenPossible: If a view controller already in the stack is of the same class as the pushed view controller, the stack is instead popped back to the existing view controller. This behavior can help users from getting lost in a deep navigation stack.
- preserve: If a view controller already in the stack is of the same class as the pushed view controller, the existing view controller is pushed to the end of the stack. This behavior is similar to a UITabBarController.
- preserveAndHideBackButton: Same as .preserve and back buttons are automatically hidden.
- replace: Any existing view controllers are released from the stack and replaced with the pushed view controller. Back buttons are automatically hidden. This behavior is ideal if view controllers require a lot of memory or their state doesn't need to be preserved..
- subMenu: Unlike all other behaviors that push using the menu's presentingViewController, this behavior pushes view controllers within the menu. Use this behavior if you want to display a sub menu.
*/
open static var menuPushStyle: MenuPushStyle = .defaultBehavior
private var _leftMenu: Protected<Menu?> = Protected(nil) { SideMenuManager.setMenu(fromMenu: $0, toMenu: $1) }
private var _rightMenu: Protected<Menu?> = Protected(nil) { SideMenuManager.setMenu(fromMenu: $0, toMenu: $1) }
/**
The presentation mode of the menu.
There are four modes in MenuPresentMode:
- menuSlideIn: Menu slides in over of the existing view.
- viewSlideOut: The existing view slides out to reveal the menu.
- viewSlideInOut: The existing view slides out while the menu slides in.
- menuDissolveIn: The menu dissolves in over the existing view controller.
*/
open static var menuPresentMode: MenuPresentMode = .viewSlideOut
/// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true.
open static var menuAllowPushOfSameClassTwice = true
/// Width of the menu when presented on screen, showing the existing view controller in the remaining space. Default is 75% of the screen width.
open static var menuWidth: CGFloat = max(round(min((appScreenRect.width), (appScreenRect.height)) * 0.75), 240)
/// Duration of the animation when the menu is presented without gestures. Default is 0.35 seconds.
open static var menuAnimationPresentDuration: Double = 0.35
/// Duration of the animation when the menu is dismissed without gestures. Default is 0.35 seconds.
open static var menuAnimationDismissDuration: Double = 0.35
/// Duration of the remaining animation when the menu is partially dismissed with gestures. Default is 0.2 seconds.
open static var menuAnimationCompleteGestureDuration: Double = 0.20
/// Amount to fade the existing view controller when the menu is presented. Default is 0 for no fade. Set to 1 to fade completely.
open static var menuAnimationFadeStrength: CGFloat = 0
/// The amount to scale the existing view controller or the menu view controller depending on the `menuPresentMode`. Default is 1 for no scaling. Less than 1 will shrink, greater than 1 will grow.
open static var menuAnimationTransformScaleFactor: CGFloat = 1
/// The background color behind menu animations. Depending on the animation settings this may not be visible. If `menuFadeStatusBar` is true, this color is used to fade it. Default is black.
open static var menuAnimationBackgroundColor: UIColor?
/// The shadow opacity around the menu view controller or existing view controller depending on the `menuPresentMode`. Default is 0.5 for 50% opacity.
open static var menuShadowOpacity: Float = 0.5
/// The shadow color around the menu view controller or existing view controller depending on the `menuPresentMode`. Default is black.
open static var menuShadowColor = UIColor.black
/// The radius of the shadow around the menu view controller or existing view controller depending on the `menuPresentMode`. Default is 5.
open static var menuShadowRadius: CGFloat = 5
/// The left menu swipe to dismiss gesture.
open static weak var menuLeftSwipeToDismissGesture: UIPanGestureRecognizer?
/// The right menu swipe to dismiss gesture.
open static weak var menuRightSwipeToDismissGesture: UIPanGestureRecognizer?
/// Enable or disable interaction with the presenting view controller while the menu is displayed. Enabling may make it difficult to dismiss the menu or cause exceptions if the user tries to present and already presented menu. Default is false.
open static var menuPresentingViewControllerUserInteractionEnabled: Bool = false
/// The strength of the parallax effect on the existing view controller. Does not apply to `menuPresentMode` when set to `ViewSlideOut`. Default is 0.
open static var menuParallaxStrength: Int = 0
/// Draws the `menuAnimationBackgroundColor` behind the status bar. Default is true.
open static var menuFadeStatusBar = true
/// The animation options when a menu is displayed. Ignored when displayed with a gesture.
open static var menuAnimationOptions: UIViewAnimationOptions = .curveEaseInOut
/// The animation spring damping when a menu is displayed. Ignored when displayed with a gesture.
open static var menuAnimationUsingSpringWithDamping: CGFloat = 1
/// The animation initial spring velocity when a menu is displayed. Ignored when displayed with a gesture.
open static var menuAnimationInitialSpringVelocity: CGFloat = 1
/// -Warning: Deprecated. Use `menuPushStyle = .subMenu` instead.
@available(*, deprecated, renamed: "menuPushStyle", message: "Use `menuPushStyle = .subMenu` instead.")
open static var menuAllowSubmenus: Bool {
get {
return menuPushStyle == .subMenu
}
set {
if newValue {
menuPushStyle = .subMenu
}
}
private var switching: Bool = false
/// Default instance of SideMenuManager.
public static let `default` = SideMenuManager()
/// Default instance of SideMenuManager (objective-C).
public class var defaultManager: SideMenuManager {
return SideMenuManager.default
}
/// -Warning: Deprecated. Use `menuPushStyle = .popWhenPossible` instead.
@available(*, deprecated, renamed: "menuPushStyle", message: "Use `menuPushStyle = .popWhenPossible` instead.")
open static var menuAllowPopIfPossible: Bool {
get {
return menuPushStyle == .popWhenPossible
}
set {
if newValue {
menuPushStyle = .popWhenPossible
}
}
}
/// -Warning: Deprecated. Use `menuPushStyle = .replace` instead.
@available(*, deprecated, renamed: "menuPushStyle", message: "Use `menuPushStyle = .replace` instead.")
open static var menuReplaceOnPush: Bool {
get {
return menuPushStyle == .replace
}
set {
if newValue {
menuPushStyle = .replace
}
}
}
/// -Warning: Deprecated. Use `menuAnimationTransformScaleFactor` instead.
@available(*, deprecated, renamed: "menuAnimationTransformScaleFactor")
open static var menuAnimationShrinkStrength: CGFloat {
get {
return menuAnimationTransformScaleFactor
}
set {
menuAnimationTransformScaleFactor = newValue
}
}
// prevent instantiation
fileprivate override init() {}
/**
The blur effect style of the menu if the menu's root view controller is a UITableViewController or UICollectionViewController.
- Note: If you want cells in a UITableViewController menu to show vibrancy, make them a subclass of UITableViewVibrantCell.
*/
open static var menuBlurEffectStyle: UIBlurEffectStyle? {
didSet {
if oldValue != menuBlurEffectStyle {
updateMenuBlurIfNecessary()
}
}
}
/// The left menu.
open static var menuLeftNavigationController: UISideMenuNavigationController? {
willSet {
if menuLeftNavigationController?.presentingViewController == nil {
removeMenuBlurForMenu(menuLeftNavigationController)
open var leftMenuNavigationController: SideMenuNavigationController? {
get {
if _leftMenu.value?.isHidden == true {
_leftMenu.value?.leftSide = true
}
return _leftMenu.value
}
didSet {
guard oldValue?.presentingViewController == nil else {
print("SideMenu Warning: menuLeftNavigationController cannot be modified while it's presented.")
menuLeftNavigationController = oldValue
return
}
setupNavigationController(menuLeftNavigationController, leftSide: true)
}
set(menu) { _leftMenu.value = menu }
}
/// The right menu.
open static var menuRightNavigationController: UISideMenuNavigationController? {
willSet {
if menuRightNavigationController?.presentingViewController == nil {
removeMenuBlurForMenu(menuRightNavigationController)
open var rightMenuNavigationController: SideMenuNavigationController? {
get {
if _rightMenu.value?.isHidden == true {
_rightMenu.value?.leftSide = false
}
return _rightMenu.value
}
didSet {
guard oldValue?.presentingViewController == nil else {
print("SideMenu Warning: menuRightNavigationController cannot be modified while it's presented.")
menuRightNavigationController = oldValue
return
}
setupNavigationController(menuRightNavigationController, leftSide: false)
}
set(menu) { _rightMenu.value = menu }
}
fileprivate class func setupNavigationController(_ forMenu: UISideMenuNavigationController?, leftSide: Bool) {
guard let forMenu = forMenu else {
return
}
if menuEnableSwipeGestures {
let exitPanGesture = UIPanGestureRecognizer()
exitPanGesture.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handleHideMenuPan(_:)))
forMenu.view.addGestureRecognizer(exitPanGesture)
if leftSide {
menuLeftSwipeToDismissGesture = exitPanGesture
} else {
menuRightSwipeToDismissGesture = exitPanGesture
}
}
forMenu.transitioningDelegate = SideMenuTransition.singleton
forMenu.modalPresentationStyle = .overFullScreen
forMenu.leftSide = leftSide
updateMenuBlurIfNecessary()
/**
Adds screen edge gestures for both left and right sides to a view to present a menu.
- Parameter toView: The view to add gestures to.
- Returns: The array of screen edge gestures added to `toView`.
*/
@discardableResult public func addScreenEdgePanGesturesToPresent(toView view: UIView) -> [UIScreenEdgePanGestureRecognizer] {
return [
addScreenEdgePanGesturesToPresent(toView: view, forMenu: .left),
addScreenEdgePanGesturesToPresent(toView: view, forMenu: .right)
]
}
/// Enable or disable gestures that would swipe to dismiss the menu. Default is true.
open static var menuEnableSwipeGestures: Bool = true {
didSet {
menuLeftSwipeToDismissGesture?.view?.removeGestureRecognizer(menuLeftSwipeToDismissGesture!)
menuRightSwipeToDismissGesture?.view?.removeGestureRecognizer(menuRightSwipeToDismissGesture!)
setupNavigationController(menuLeftNavigationController, leftSide: true)
setupNavigationController(menuRightNavigationController, leftSide: false)
}
}
fileprivate class func updateMenuBlurIfNecessary() {
let menuBlurBlock = { (forMenu: UISideMenuNavigationController?) in
if let forMenu = forMenu {
setupMenuBlurForMenu(forMenu)
}
}
menuBlurBlock(menuLeftNavigationController)
menuBlurBlock(menuRightNavigationController)
}
fileprivate class func setupMenuBlurForMenu(_ forMenu: UISideMenuNavigationController?) {
removeMenuBlurForMenu(forMenu)
guard let forMenu = forMenu,
let menuBlurEffectStyle = menuBlurEffectStyle,
let view = forMenu.visibleViewController?.view
, !UIAccessibilityIsReduceTransparencyEnabled() else {
return
}
if forMenu.originalMenuBackgroundColor == nil {
forMenu.originalMenuBackgroundColor = view.backgroundColor
}
let blurEffect = UIBlurEffect(style: menuBlurEffectStyle)
let blurView = UIVisualEffectView(effect: blurEffect)
view.backgroundColor = UIColor.clear
if let tableViewController = forMenu.visibleViewController as? UITableViewController {
tableViewController.tableView.backgroundView = blurView
tableViewController.tableView.separatorEffect = UIVibrancyEffect(blurEffect: blurEffect)
tableViewController.tableView.reloadData()
} else {
blurView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
blurView.frame = view.bounds
view.insertSubview(blurView, at: 0)
}
}
fileprivate class func removeMenuBlurForMenu(_ forMenu: UISideMenuNavigationController?) {
guard let forMenu = forMenu,
let originalMenuBackgroundColor = forMenu.originalMenuBackgroundColor,
let view = forMenu.visibleViewController?.view else {
return
}
view.backgroundColor = originalMenuBackgroundColor
forMenu.originalMenuBackgroundColor = nil
if let tableViewController = forMenu.visibleViewController as? UITableViewController {
tableViewController.tableView.backgroundView = nil
tableViewController.tableView.separatorEffect = nil
tableViewController.tableView.reloadData()
} else if let blurView = view.subviews[0] as? UIVisualEffectView {
blurView.removeFromSuperview()
}
}
/**
Adds screen edge gestures to a view to present a menu.
- Parameter toView: The view to add gestures to.
- Parameter forMenu: The menu (left or right) you want to add a gesture for. If unspecified, gestures will be added for both sides.
- Parameter forMenu: The menu (left or right) you want to add a gesture for.
- Returns: The array of screen edge gestures added to `toView`.
- Returns: The screen edge gestures added to `toView`.
*/
@discardableResult open class func menuAddScreenEdgePanGesturesToPresent(toView: UIView, forMenu:UIRectEdge? = nil) -> [UIScreenEdgePanGestureRecognizer] {
var array = [UIScreenEdgePanGestureRecognizer]()
if forMenu != .right {
let leftScreenEdgeGestureRecognizer = UIScreenEdgePanGestureRecognizer()
leftScreenEdgeGestureRecognizer.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handlePresentMenuLeftScreenEdge(_:)))
leftScreenEdgeGestureRecognizer.edges = .left
leftScreenEdgeGestureRecognizer.cancelsTouchesInView = true
toView.addGestureRecognizer(leftScreenEdgeGestureRecognizer)
array.append(leftScreenEdgeGestureRecognizer)
if SideMenuManager.menuLeftNavigationController == nil {
print("SideMenu Warning: menuAddScreenEdgePanGesturesToPresent for the left side was called before menuLeftNavigationController has been defined. The gesture will not work without a menu.")
}
@discardableResult public func addScreenEdgePanGesturesToPresent(toView view: UIView, forMenu side: PresentDirection) -> UIScreenEdgePanGestureRecognizer {
if menu(forSide: side) == nil {
let methodName = #function // "addScreenEdgePanGesturesToPresent"
let suggestedMethodName = "addScreenEdgePanGesturesToPresent(toView:forMenu:))"
Print.warning(.screenGestureAdded, arguments: methodName, side.name, suggestedMethodName)
}
if forMenu != .left {
let rightScreenEdgeGestureRecognizer = UIScreenEdgePanGestureRecognizer()
rightScreenEdgeGestureRecognizer.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handlePresentMenuRightScreenEdge(_:)))
rightScreenEdgeGestureRecognizer.edges = .right
rightScreenEdgeGestureRecognizer.cancelsTouchesInView = true
toView.addGestureRecognizer(rightScreenEdgeGestureRecognizer)
array.append(rightScreenEdgeGestureRecognizer)
if SideMenuManager.menuRightNavigationController == nil {
print("SideMenu Warning: menuAddScreenEdgePanGesturesToPresent for the right side was called before menuRightNavigationController has been defined. The gesture will not work without a menu.")
}
}
return array
return self.addScreenEdgeGesture(to: view, edge: side.edge)
}
/**
@@ -357,15 +109,121 @@ open class SideMenuManager : NSObject {
- Returns: The pan gesture added to `toView`.
*/
@discardableResult open class func menuAddPanGestureToPresent(toView: UIView) -> UIPanGestureRecognizer {
let panGestureRecognizer = UIPanGestureRecognizer()
panGestureRecognizer.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handlePresentMenuPan(_:)))
toView.addGestureRecognizer(panGestureRecognizer)
if SideMenuManager.menuLeftNavigationController ?? SideMenuManager.menuRightNavigationController == nil {
print("SideMenu Warning: menuAddPanGestureToPresent called before menuLeftNavigationController or menuRightNavigationController have been defined. Gestures will not work without a menu.")
@discardableResult public func addPanGestureToPresent(toView view: UIView) -> UIPanGestureRecognizer {
if leftMenuNavigationController ?? rightMenuNavigationController == nil {
Print.warning(.panGestureAdded, arguments: #function, PresentDirection.left.name, PresentDirection.right.name, required: true)
}
return panGestureRecognizer
return addPresentPanGesture(to: view)
}
}
internal extension SideMenuManager {
func setMenu(_ menu: Menu?, forLeftSide leftSide: Bool) {
switch leftSide {
case true: leftMenuNavigationController = menu
case false: rightMenuNavigationController = menu
}
}
private class func setMenu(fromMenu: Menu?, toMenu: Menu?) -> Menu? {
if fromMenu?.isHidden == false {
Print.warning(.menuInUse, arguments: PresentDirection.left.name, required: true)
return fromMenu
}
return toMenu
}
}
private extension SideMenuManager {
@objc func handlePresentMenuScreenEdge(_ gesture: UIScreenEdgePanGestureRecognizer) {
handleMenuPan(gesture)
}
@objc func handlePresentMenuPan(_ gesture: UIPanGestureRecognizer) {
handleMenuPan(gesture)
}
func handleMenuPan(_ gesture: UIPanGestureRecognizer) {
if let activeMenu = activeMenu {
let width = activeMenu.menuWidth
let distance = gesture.xTranslation / width
switch (gesture.state) {
case .changed:
if gesture.canSwitch {
switching = (distance > 0 && !activeMenu.leftSide) || (distance < 0 && activeMenu.leftSide)
if switching {
activeMenu.cancelMenuPan(gesture)
return
}
}
default:
switching = false
}
} else {
let leftSide: Bool
if let gesture = gesture as? UIScreenEdgePanGestureRecognizer {
leftSide = gesture.edges.contains(.left)
} else {
// not sure which way the user is swiping yet, so do nothing
if gesture.xTranslation == 0 { return }
leftSide = gesture.xTranslation > 0
}
guard let menu = menu(forLeftSide: leftSide) else { return }
menu.present(from: topMostViewController, interactively: true)
}
activeMenu?.handleMenuPan(gesture, true)
}
var activeMenu: Menu? {
if leftMenuNavigationController?.isHidden == false { return leftMenuNavigationController }
if rightMenuNavigationController?.isHidden == false { return rightMenuNavigationController }
return nil
}
func menu(forSide: PresentDirection) -> Menu? {
switch forSide {
case .left: return leftMenuNavigationController
case .right: return rightMenuNavigationController
}
}
func menu(forLeftSide leftSide: Bool) -> Menu? {
return menu(forSide: leftSide ? .left : .right)
}
func addScreenEdgeGesture(to view: UIView, edge: UIRectEdge) -> UIScreenEdgePanGestureRecognizer {
if let screenEdgeGestureRecognizer = view.gestureRecognizers?.first(where: { $0 is SideMenuScreenEdgeGestureRecognizer }) as? SideMenuScreenEdgeGestureRecognizer,
screenEdgeGestureRecognizer.edges == edge {
screenEdgeGestureRecognizer.remove()
}
return SideMenuScreenEdgeGestureRecognizer(addTo: view, target: self, action: #selector(handlePresentMenuScreenEdge(_:))).with {
$0.edges = edge
}
}
@discardableResult func addPresentPanGesture(to view: UIView) -> UIPanGestureRecognizer {
if let panGestureRecognizer = view.gestureRecognizers?.first(where: { $0 is SideMenuPanGestureRecognizer }) as? SideMenuPanGestureRecognizer {
return panGestureRecognizer
}
return SideMenuPanGestureRecognizer(addTo: view, target: self, action: #selector(handlePresentMenuPan(_:)))
}
var topMostViewController: UIViewController? {
return UIApplication.shared.keyWindow?.rootViewController?.topMostViewController
}
}
extension SideMenuManager: SideMenuNavigationControllerTransitionDelegate {
internal func sideMenuTransitionDidDismiss(menu: Menu) {
defer { switching = false }
guard switching, let switchToMenu = self.menu(forLeftSide: !menu.leftSide) else { return }
switchToMenu.present(from: topMostViewController, interactively: true)
}
}
@@ -0,0 +1,656 @@
//
// SideMenuNavigationController.swift
//
// Created by Jon Kent on 1/14/16.
// Copyright © 2016 Jon Kent. All rights reserved.
//
import UIKit
@objc public enum SideMenuPushStyle: Int { case
`default`,
popWhenPossible,
preserve,
preserveAndHideBackButton,
replace,
subMenu
internal var hidesBackButton: Bool {
switch self {
case .preserveAndHideBackButton, .replace: return true
case .default, .popWhenPossible, .preserve, .subMenu: return false
}
}
}
internal protocol MenuModel {
/// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true.
var allowPushOfSameClassTwice: Bool { get }
/// Forces menus to always animate when appearing or disappearing, regardless of a pushed view controller's animation.
var alwaysAnimate: Bool { get }
/**
The blur effect style of the menu if the menu's root view controller is a UITableViewController or UICollectionViewController.
- Note: If you want cells in a UITableViewController menu to show vibrancy, make them a subclass of UITableViewVibrantCell.
*/
var blurEffectStyle: UIBlurEffect.Style? { get }
/// Animation curve of the remaining animation when the menu is partially dismissed with gestures. Default is .easeIn.
var completionCurve: UIView.AnimationCurve { get }
/// Automatically dismisses the menu when another view is presented from it.
var dismissOnPresent: Bool { get }
/// Automatically dismisses the menu when another view controller is pushed from it.
var dismissOnPush: Bool { get }
/// Automatically dismisses the menu when the screen is rotated.
var dismissOnRotation: Bool { get }
/// Automatically dismisses the menu when app goes to the background.
var dismissWhenBackgrounded: Bool { get }
/// Enable or disable a swipe gesture that dismisses the menu. Will not be triggered when `presentingViewControllerUserInteractionEnabled` is set to true. Default is true.
var enableSwipeToDismissGesture: Bool { get }
/// Enable or disable a tap gesture that dismisses the menu. Will not be triggered when `presentingViewControllerUserInteractionEnabled` is set to true. Default is true.
var enableTapToDismissGesture: Bool { get }
/**
The push style of the menu.
There are six modes in MenuPushStyle:
- defaultBehavior: The view controller is pushed onto the stack.
- popWhenPossible: If a view controller already in the stack is of the same class as the pushed view controller, the stack is instead popped back to the existing view controller. This behavior can help users from getting lost in a deep navigation stack.
- preserve: If a view controller already in the stack is of the same class as the pushed view controller, the existing view controller is pushed to the end of the stack. This behavior is similar to a UITabBarController.
- preserveAndHideBackButton: Same as .preserve and back buttons are automatically hidden.
- replace: Any existing view controllers are released from the stack and replaced with the pushed view controller. Back buttons are automatically hidden. This behavior is ideal if view controllers require a lot of memory or their state doesn't need to be preserved..
- subMenu: Unlike all other behaviors that push using the menu's presentingViewController, this behavior pushes view controllers within the menu. Use this behavior if you want to display a sub menu.
*/
var pushStyle: SideMenuPushStyle { get }
}
@objc public protocol SideMenuNavigationControllerDelegate {
@objc optional func sideMenuWillAppear(menu: SideMenuNavigationController, animated: Bool)
@objc optional func sideMenuDidAppear(menu: SideMenuNavigationController, animated: Bool)
@objc optional func sideMenuWillDisappear(menu: SideMenuNavigationController, animated: Bool)
@objc optional func sideMenuDidDisappear(menu: SideMenuNavigationController, animated: Bool)
}
internal protocol SideMenuNavigationControllerTransitionDelegate: class {
func sideMenuTransitionDidDismiss(menu: Menu)
}
public struct SideMenuSettings: Model, InitializableStruct {
public var allowPushOfSameClassTwice: Bool = true
public var alwaysAnimate: Bool = true
public var animationOptions: UIView.AnimationOptions = .curveEaseInOut
public var blurEffectStyle: UIBlurEffect.Style? = nil
public var completeGestureDuration: Double = 0.35
public var completionCurve: UIView.AnimationCurve = .easeIn
public var dismissDuration: Double = 0.35
public var dismissOnPresent: Bool = true
public var dismissOnPush: Bool = true
public var dismissOnRotation: Bool = true
public var dismissWhenBackgrounded: Bool = true
public var enableSwipeToDismissGesture: Bool = true
public var enableTapToDismissGesture: Bool = true
public var initialSpringVelocity: CGFloat = 1
public var menuWidth: CGFloat = {
let appScreenRect = UIApplication.shared.keyWindow?.bounds ?? UIWindow().bounds
let minimumSize = min(appScreenRect.width, appScreenRect.height)
return min(round(minimumSize * 0.75), 240)
}()
public var presentingViewControllerUserInteractionEnabled: Bool = false
public var presentingViewControllerUseSnapshot: Bool = false
public var presentDuration: Double = 0.35
public var presentationStyle: SideMenuPresentationStyle = .viewSlideOut
public var pushStyle: SideMenuPushStyle = .default
public var statusBarEndAlpha: CGFloat = 0
public var usingSpringWithDamping: CGFloat = 1
public init() {}
}
internal typealias Menu = SideMenuNavigationController
typealias Model = MenuModel & PresentationModel & AnimationModel
@objcMembers
open class SideMenuNavigationController: UINavigationController {
private lazy var _leftSide = Protected(false) { [weak self] oldValue, newValue in
guard self?.isHidden != false else {
Print.warning(.property, arguments: .leftSide, required: true)
return oldValue
}
return newValue
}
private weak var _sideMenuManager: SideMenuManager?
private weak var foundViewController: UIViewController?
private var originalBackgroundColor: UIColor?
private var rotating: Bool = false
private var transitionController: SideMenuTransitionController?
private var transitionInteractive: Bool = false
/// Delegate for receiving appear and disappear related events. If `nil` the visible view controller that displays a `SideMenuNavigationController` automatically receives these events.
public weak var sideMenuDelegate: SideMenuNavigationControllerDelegate?
/// The swipe to dismiss gesture.
open private(set) weak var swipeToDismissGesture: UIPanGestureRecognizer? = nil
/// The tap to dismiss gesture.
open private(set) weak var tapToDismissGesture: UITapGestureRecognizer? = nil
open var sideMenuManager: SideMenuManager {
get { return _sideMenuManager ?? SideMenuManager.default }
set {
newValue.setMenu(self, forLeftSide: leftSide)
if let sideMenuManager = _sideMenuManager, sideMenuManager !== newValue {
let side = SideMenuManager.PresentDirection(leftSide: leftSide)
Print.warning(.menuAlreadyAssigned, arguments: String(describing: self.self), side.name, String(describing: newValue))
}
_sideMenuManager = newValue
}
}
/// The menu settings.
open var settings = SideMenuSettings() {
didSet {
setupBlur()
if !enableSwipeToDismissGesture {
swipeToDismissGesture?.remove()
}
if !enableTapToDismissGesture {
tapToDismissGesture?.remove()
}
}
}
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
setup()
}
public init(rootViewController: UIViewController, settings: SideMenuSettings = SideMenuSettings()) {
self.settings = settings
super.init(rootViewController: rootViewController)
setup()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override open func awakeFromNib() {
super.awakeFromNib()
sideMenuManager.setMenu(self, forLeftSide: leftSide)
}
override open func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if topViewController == nil {
Print.warning(.emptyMenu)
}
// Dismiss keyboard to prevent weird keyboard animations from occurring during transition
presentingViewController?.view.endEditing(true)
foundViewController = nil
activeDelegate?.sideMenuWillAppear?(menu: self, animated: animated)
}
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// We had presented a view before, so lets dismiss ourselves as already acted upon
if view.isHidden {
dismiss(animated: false, completion: { [weak self] in
self?.view.isHidden = false
})
} else {
activeDelegate?.sideMenuDidAppear?(menu: self, animated: animated)
}
}
override open func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
defer { activeDelegate?.sideMenuWillDisappear?(menu: self, animated: animated) }
guard !isBeingDismissed else { return }
// When presenting a view controller from the menu, the menu view gets moved into another transition view above our transition container
// which can break the visual layout we had before. So, we move the menu view back to its original transition view to preserve it.
if let presentingView = presentingViewController?.view, let containerView = presentingView.superview {
containerView.addSubview(view)
}
if dismissOnPresent {
// We're presenting a view controller from the menu, so we need to hide the menu so it isn't showing when the presented view is dismissed.
transitionController?.transition(presenting: false, animated: animated, alongsideTransition: { [weak self] in
guard let self = self else { return }
self.activeDelegate?.sideMenuWillDisappear?(menu: self, animated: animated)
}, complete: false, completion: { [weak self] _ in
guard let self = self else { return }
self.activeDelegate?.sideMenuDidDisappear?(menu: self, animated: animated)
self.view.isHidden = true
})
}
}
override open func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// Work-around: if the menu is dismissed without animation the transition logic is never called to restore the
// the view hierarchy leaving the screen black/empty. This is because the transition moves views within a container
// view, but dismissing without animation removes the container view before the original hierarchy is restored.
// This check corrects that.
if isBeingDismissed {
transitionController?.transition(presenting: false, animated: false)
}
// Clear selection on UITableViewControllers when reappearing using custom transitions
if let tableViewController = topViewController as? UITableViewController,
let tableView = tableViewController.tableView,
let indexPaths = tableView.indexPathsForSelectedRows,
tableViewController.clearsSelectionOnViewWillAppear {
indexPaths.forEach { tableView.deselectRow(at: $0, animated: false) }
}
activeDelegate?.sideMenuDidDisappear?(menu: self, animated: animated)
if isBeingDismissed {
transitionController = nil
} else if dismissOnPresent {
view.isHidden = true
}
}
override open func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
// Don't bother resizing if the view isn't visible
guard let transitionController = transitionController, !view.isHidden else { return }
rotating = true
let dismiss = self.presentingViewControllerUseSnapshot || self.dismissOnRotation
coordinator.animate(alongsideTransition: { _ in
if dismiss {
transitionController.transition(presenting: false, animated: false, complete: false)
} else {
transitionController.layout()
}
}) { [weak self] _ in
guard let self = self else { return }
if dismiss {
self.dismissMenu(animated: false)
}
self.rotating = false
}
}
open override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
transitionController?.layout()
}
override open func pushViewController(_ viewController: UIViewController, animated: Bool) {
guard viewControllers.count > 0 else {
// NOTE: pushViewController is called by init(rootViewController: UIViewController)
// so we must perform the normal super method in this case
return super.pushViewController(viewController, animated: animated)
}
var alongsideTransition: (() -> Void)? = nil
if dismissOnPush {
alongsideTransition = { [weak self] in
guard let self = self else { return }
self.dismissAnimation(animated: animated || self.alwaysAnimate)
}
}
let pushed = SideMenuPushCoordinator(config:
.init(
allowPushOfSameClassTwice: allowPushOfSameClassTwice,
alongsideTransition: alongsideTransition,
animated: animated,
fromViewController: self,
pushStyle: pushStyle,
toViewController: viewController
)
).start()
if !pushed {
super.pushViewController(viewController, animated: animated)
}
}
override open var transitioningDelegate: UIViewControllerTransitioningDelegate? {
get {
guard transitionController == nil else { return transitionController }
transitionController = SideMenuTransitionController(leftSide: leftSide, config: settings)
transitionController?.delegate = self
transitionController?.interactive = transitionInteractive
transitionInteractive = false
return transitionController
}
set { Print.warning(.transitioningDelegate, required: true) }
}
}
// Interface
extension SideMenuNavigationController: Model {
@IBInspectable open var allowPushOfSameClassTwice: Bool {
get { return settings.allowPushOfSameClassTwice }
set { settings.allowPushOfSameClassTwice = newValue }
}
@IBInspectable open var alwaysAnimate: Bool {
get { return settings.alwaysAnimate }
set { settings.alwaysAnimate = newValue }
}
@IBInspectable open var animationOptions: UIView.AnimationOptions {
get { return settings.animationOptions }
set { settings.animationOptions = newValue }
}
open var blurEffectStyle: UIBlurEffect.Style? {
get { return settings.blurEffectStyle }
set { settings.blurEffectStyle = newValue }
}
@IBInspectable open var completeGestureDuration: Double {
get { return settings.completeGestureDuration }
set { settings.completeGestureDuration = newValue }
}
@IBInspectable open var completionCurve: UIView.AnimationCurve {
get { return settings.completionCurve }
set { settings.completionCurve = newValue }
}
@IBInspectable open var dismissDuration: Double {
get { return settings.dismissDuration }
set { settings.dismissDuration = newValue }
}
@IBInspectable open var dismissOnPresent: Bool {
get { return settings.dismissOnPresent }
set { settings.dismissOnPresent = newValue }
}
@IBInspectable open var dismissOnPush: Bool {
get { return settings.dismissOnPush }
set { settings.dismissOnPush = newValue }
}
@IBInspectable open var dismissOnRotation: Bool {
get { return settings.dismissOnRotation }
set { settings.dismissOnRotation = newValue }
}
@IBInspectable open var dismissWhenBackgrounded: Bool {
get { return settings.dismissWhenBackgrounded }
set { settings.dismissWhenBackgrounded = newValue }
}
@IBInspectable open var enableSwipeToDismissGesture: Bool {
get { return settings.enableSwipeToDismissGesture }
set { settings.enableSwipeToDismissGesture = newValue }
}
@IBInspectable open var enableTapToDismissGesture: Bool {
get { return settings.enableTapToDismissGesture }
set { settings.enableTapToDismissGesture = newValue }
}
@IBInspectable open var initialSpringVelocity: CGFloat {
get { return settings.initialSpringVelocity }
set { settings.initialSpringVelocity = newValue }
}
/// Whether the menu appears on the right or left side of the screen. Right is the default. This property cannot be changed after the menu has loaded.
@IBInspectable open var leftSide: Bool {
get { return _leftSide.value }
set { _leftSide.value = newValue }
}
/// Indicates if the menu is anywhere in the view hierarchy, even if covered by another view controller.
open override var isHidden: Bool {
return super.isHidden
}
@IBInspectable open var menuWidth: CGFloat {
get { return settings.menuWidth }
set { settings.menuWidth = newValue }
}
@IBInspectable open var presentingViewControllerUserInteractionEnabled: Bool {
get { return settings.presentingViewControllerUserInteractionEnabled }
set { settings.presentingViewControllerUserInteractionEnabled = newValue }
}
@IBInspectable open var presentingViewControllerUseSnapshot: Bool {
get { return settings.presentingViewControllerUseSnapshot }
set { settings.presentingViewControllerUseSnapshot = newValue }
}
@IBInspectable open var presentDuration: Double {
get { return settings.presentDuration }
set { settings.presentDuration = newValue }
}
open var presentationStyle: SideMenuPresentationStyle {
get { return settings.presentationStyle }
set { settings.presentationStyle = newValue }
}
@IBInspectable open var pushStyle: SideMenuPushStyle {
get { return settings.pushStyle }
set { settings.pushStyle = newValue }
}
@IBInspectable open var statusBarEndAlpha: CGFloat {
get { return settings.statusBarEndAlpha }
set { settings.statusBarEndAlpha = newValue }
}
@IBInspectable open var usingSpringWithDamping: CGFloat {
get { return settings.usingSpringWithDamping }
set { settings.usingSpringWithDamping = newValue }
}
}
extension SideMenuNavigationController: SideMenuTransitionControllerDelegate {
func sideMenuTransitionController(_ transitionController: SideMenuTransitionController, didDismiss viewController: UIViewController) {
sideMenuManager.sideMenuTransitionDidDismiss(menu: self)
}
func sideMenuTransitionController(_ transitionController: SideMenuTransitionController, didPresent viewController: UIViewController) {
swipeToDismissGesture?.remove()
swipeToDismissGesture = addSwipeToDismissGesture(to: view.superview)
tapToDismissGesture = addTapToDismissGesture(to: view.superview)
}
}
internal extension SideMenuNavigationController {
func handleMenuPan(_ gesture: UIPanGestureRecognizer, _ presenting: Bool) {
let width = menuWidth
let distance = gesture.xTranslation / width
let progress = max(min(distance * factor(presenting), 1), 0)
switch (gesture.state) {
case .began:
if !presenting {
dismissMenu(interactively: true)
}
fallthrough
case .changed:
transitionController?.handle(state: .update(progress: progress))
case .ended:
let velocity = gesture.xVelocity * factor(presenting)
let finished = velocity >= 100 || velocity >= -50 && abs(progress) >= 0.5
transitionController?.handle(state: finished ? .finish : .cancel)
default:
transitionController?.handle(state: .cancel)
}
}
func cancelMenuPan(_ gesture: UIPanGestureRecognizer) {
transitionController?.handle(state: .cancel)
}
func dismissMenu(animated flag: Bool = true, interactively: Bool = false, completion: (() -> Void)? = nil) {
guard !isHidden else { return }
transitionController?.interactive = interactively
dismiss(animated: flag, completion: completion)
}
// Note: although this method is syntactically reversed it allows the interactive property to scoped privately
func present(from viewController: UIViewController?, interactively: Bool, completion: (() -> Void)? = nil) {
guard let viewController = viewController else { return }
transitionInteractive = interactively
viewController.present(self, animated: true, completion: completion)
}
}
private extension SideMenuNavigationController {
weak var activeDelegate: SideMenuNavigationControllerDelegate? {
guard !view.isHidden else { return nil }
if let sideMenuDelegate = sideMenuDelegate { return sideMenuDelegate }
return findViewController as? SideMenuNavigationControllerDelegate
}
var findViewController: UIViewController? {
foundViewController = foundViewController ?? presentingViewController?.activeViewController
return foundViewController
}
func dismissAnimation(animated: Bool) {
transitionController?.transition(presenting: false, animated: animated, alongsideTransition: { [weak self] in
guard let self = self else { return }
self.activeDelegate?.sideMenuWillDisappear?(menu: self, animated: animated)
}, completion: { [weak self] _ in
guard let self = self else { return }
self.activeDelegate?.sideMenuDidDisappear?(menu: self, animated: animated)
self.dismiss(animated: false, completion: nil)
self.foundViewController = nil
})
}
func setup() {
modalPresentationStyle = .overFullScreen
setupBlur()
if #available(iOS 13.0, *) {} else {
registerForNotifications()
}
}
func setupBlur() {
removeBlur()
guard let blurEffectStyle = blurEffectStyle,
let view = topViewController?.view,
!UIAccessibility.isReduceTransparencyEnabled else {
return
}
originalBackgroundColor = originalBackgroundColor ?? view.backgroundColor
let blurEffect = UIBlurEffect(style: blurEffectStyle)
let blurView = UIVisualEffectView(effect: blurEffect)
view.backgroundColor = UIColor.clear
if let tableViewController = topViewController as? UITableViewController {
tableViewController.tableView.backgroundView = blurView
tableViewController.tableView.separatorEffect = UIVibrancyEffect(blurEffect: blurEffect)
tableViewController.tableView.reloadData()
} else {
blurView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
blurView.frame = view.bounds
view.insertSubview(blurView, at: 0)
}
}
func removeBlur() {
guard let originalBackgroundColor = originalBackgroundColor,
let view = topViewController?.view else {
return
}
self.originalBackgroundColor = nil
view.backgroundColor = originalBackgroundColor
if let tableViewController = topViewController as? UITableViewController {
tableViewController.tableView.backgroundView = nil
tableViewController.tableView.separatorEffect = nil
tableViewController.tableView.reloadData()
} else if let blurView = view.subviews.first as? UIVisualEffectView {
blurView.removeFromSuperview()
}
}
@available(iOS, deprecated: 13.0)
func registerForNotifications() {
NotificationCenter.default.removeObserver(self)
[UIApplication.willChangeStatusBarFrameNotification,
UIApplication.didEnterBackgroundNotification].forEach {
NotificationCenter.default.addObserver(self, selector: #selector(handleNotification), name: $0, object: nil)
}
}
@available(iOS, deprecated: 13.0)
@objc func handleNotification(notification: NSNotification) {
guard isHidden else { return }
switch notification.name {
case UIApplication.willChangeStatusBarFrameNotification:
// Dismiss for in-call status bar changes but not rotation
if !rotating {
dismissMenu()
}
case UIApplication.didEnterBackgroundNotification:
if dismissWhenBackgrounded {
dismissMenu()
}
default: break
}
}
@discardableResult func addSwipeToDismissGesture(to view: UIView?) -> UIPanGestureRecognizer? {
guard enableSwipeToDismissGesture else { return nil }
return UIPanGestureRecognizer(addTo: view, target: self, action: #selector(handleDismissMenuPan(_:)))?.with {
$0.cancelsTouchesInView = false
}
}
@discardableResult func addTapToDismissGesture(to view: UIView?) -> UITapGestureRecognizer? {
guard enableTapToDismissGesture else { return nil }
return UITapGestureRecognizer(addTo: view, target: self, action: #selector(handleDismissMenuTap(_:)))?.with {
$0.cancelsTouchesInView = false
}
}
@objc func handleDismissMenuTap(_ tap: UITapGestureRecognizer) {
let hitTest = view.window?.hitTest(tap.location(in: view.superview), with: nil)
guard hitTest == view.superview else { return }
dismissMenu()
}
@objc func handleDismissMenuPan(_ gesture: UIPanGestureRecognizer) {
handleMenuPan(gesture, false)
}
func factor(_ presenting: Bool) -> CGFloat {
return presenting ? presentFactor : hideFactor
}
var presentFactor: CGFloat {
return leftSide ? 1 : -1
}
var hideFactor: CGFloat {
return -presentFactor
}
}
@@ -0,0 +1,316 @@
//
// BasePresentationController.swift
// SideMenu
//
// Created by Jon Kent on 10/20/18.
//
import UIKit
internal protocol PresentationModel {
/// Draws `presentStyle.backgroundColor` behind the status bar. Default is 1.
var statusBarEndAlpha: CGFloat { get }
/// Enable or disable interaction with the presenting view controller while the menu is displayed. Enabling may make it difficult to dismiss the menu or cause exceptions if the user tries to present and already presented menu. `presentingViewControllerUseSnapshot` must also set to false. Default is false.
var presentingViewControllerUserInteractionEnabled: Bool { get }
/// Use a snapshot for the presenting vierw controller while the menu is displayed. Useful when layout changes occur during transitions. Not recommended for apps that support rotation. Default is false.
var presentingViewControllerUseSnapshot: Bool { get }
/// The presentation style of the menu.
var presentationStyle: SideMenuPresentationStyle { get }
/// Width of the menu when presented on screen, showing the existing view controller in the remaining space. Default is zero.
var menuWidth: CGFloat { get }
}
internal protocol SideMenuPresentationControllerDelegate: class {
func sideMenuPresentationControllerDidTap(_ presentationController: SideMenuPresentationController)
func sideMenuPresentationController(_ presentationController: SideMenuPresentationController, didPanWith gesture: UIPanGestureRecognizer)
}
internal final class SideMenuPresentationController {
private let config: PresentationModel
private weak var containerView: UIView?
private var interactivePopGestureRecognizerEnabled: Bool?
private var clipsToBounds: Bool?
private let leftSide: Bool
private weak var presentedViewController: UIViewController?
private weak var presentingViewController: UIViewController?
private lazy var snapshotView: UIView? = {
guard config.presentingViewControllerUseSnapshot,
let view = presentingViewController?.view.snapshotView(afterScreenUpdates: true) else {
return nil
}
view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
return view
}()
private lazy var statusBarView: UIView? = {
guard config.statusBarEndAlpha > .leastNonzeroMagnitude else { return nil }
return UIView {
$0.backgroundColor = config.presentationStyle.backgroundColor
$0.autoresizingMask = [.flexibleHeight, .flexibleWidth]
$0.isUserInteractionEnabled = false
}
}()
required init(config: PresentationModel, leftSide: Bool, presentedViewController: UIViewController, presentingViewController: UIViewController, containerView: UIView) {
self.config = config
self.containerView = containerView
self.leftSide = leftSide
self.presentedViewController = presentedViewController
self.presentingViewController = presentingViewController
}
deinit {
guard presentedViewController?.isHidden == false else { return }
// Presentations must be reversed to preserve user experience
dismissalTransitionWillBegin()
dismissalTransition()
dismissalTransitionDidEnd(true)
}
func containerViewWillLayoutSubviews() {
guard let containerView = containerView,
let presentedViewController = presentedViewController,
let presentingViewController = presentingViewController
else { return }
presentedViewController.view.untransform {
presentedViewController.view.frame = frameOfPresentedViewInContainerView
}
presentingViewController.view.untransform {
presentingViewController.view.frame = frameOfPresentingViewInContainerView
snapshotView?.frame = presentingViewController.view.bounds
}
guard let statusBarView = statusBarView else { return }
var statusBarFrame: CGRect = self.statusBarFrame
statusBarFrame.size.height -= containerView.frame.minY
statusBarView.frame = statusBarFrame
}
func presentationTransitionWillBegin() {
guard let containerView = containerView,
let presentedViewController = presentedViewController,
let presentingViewController = presentingViewController
else { return }
if let snapshotView = snapshotView {
presentingViewController.view.addSubview(snapshotView)
}
presentingViewController.view.isUserInteractionEnabled = config.presentingViewControllerUserInteractionEnabled
containerView.backgroundColor = config.presentationStyle.backgroundColor
layerViews()
if let statusBarView = statusBarView {
containerView.addSubview(statusBarView)
}
dismissalTransition()
config.presentationStyle.presentationTransitionWillBegin(to: presentedViewController, from: presentingViewController)
}
func presentationTransition() {
guard let presentedViewController = presentedViewController,
let presentingViewController = presentingViewController
else { return }
transition(
to: presentedViewController,
from: presentingViewController,
alpha: config.presentationStyle.presentingEndAlpha,
statusBarAlpha: config.statusBarEndAlpha,
scale: config.presentationStyle.presentingScaleFactor,
translate: config.presentationStyle.presentingTranslateFactor
)
config.presentationStyle.presentationTransition(to: presentedViewController, from: presentingViewController)
}
func presentationTransitionDidEnd(_ completed: Bool) {
guard completed else {
snapshotView?.removeFromSuperview()
dismissalTransitionDidEnd(!completed)
return
}
guard let presentedViewController = presentedViewController,
let presentingViewController = presentingViewController
else { return }
addParallax(to: presentingViewController.view)
if let topNavigationController = presentingViewController as? UINavigationController {
interactivePopGestureRecognizerEnabled = interactivePopGestureRecognizerEnabled ?? topNavigationController.interactivePopGestureRecognizer?.isEnabled
topNavigationController.interactivePopGestureRecognizer?.isEnabled = false
}
containerViewWillLayoutSubviews()
config.presentationStyle.presentationTransitionDidEnd(to: presentedViewController, from: presentingViewController, completed)
}
func dismissalTransitionWillBegin() {
snapshotView?.removeFromSuperview()
presentationTransition()
guard let presentedViewController = presentedViewController,
let presentingViewController = presentingViewController
else { return }
config.presentationStyle.dismissalTransitionWillBegin(to: presentedViewController, from: presentingViewController)
}
func dismissalTransition() {
guard let presentedViewController = presentedViewController,
let presentingViewController = presentingViewController
else { return }
transition(
to: presentingViewController,
from: presentedViewController,
alpha: config.presentationStyle.menuStartAlpha,
statusBarAlpha: 0,
scale: config.presentationStyle.menuScaleFactor,
translate: config.presentationStyle.menuTranslateFactor
)
config.presentationStyle.dismissalTransition(to: presentedViewController, from: presentingViewController)
}
func dismissalTransitionDidEnd(_ completed: Bool) {
guard completed else {
if let snapshotView = snapshotView, let presentingViewController = presentingViewController {
presentingViewController.view.addSubview(snapshotView)
}
presentationTransitionDidEnd(!completed)
return
}
guard let presentedViewController = presentedViewController,
let presentingViewController = presentingViewController
else { return }
statusBarView?.removeFromSuperview()
removeStyles(from: presentingViewController.containerViewController.view)
if let interactivePopGestureRecognizerEnabled = interactivePopGestureRecognizerEnabled,
let topNavigationController = presentingViewController as? UINavigationController {
topNavigationController.interactivePopGestureRecognizer?.isEnabled = interactivePopGestureRecognizerEnabled
}
presentingViewController.view.isUserInteractionEnabled = true
config.presentationStyle.dismissalTransitionDidEnd(to: presentedViewController, from: presentingViewController, completed)
}
}
private extension SideMenuPresentationController {
var statusBarFrame: CGRect {
if #available(iOS 13.0, *) {
return containerView?.window?.windowScene?.statusBarManager?.statusBarFrame ?? .zero
} else {
return UIApplication.shared.statusBarFrame
}
}
var frameOfPresentedViewInContainerView: CGRect {
guard let containerView = containerView else { return .zero }
var rect = containerView.bounds
rect.origin.x = leftSide ? 0 : rect.width - config.menuWidth
rect.size.width = config.menuWidth
return rect
}
var frameOfPresentingViewInContainerView: CGRect {
guard let containerView = containerView else { return .zero }
var rect = containerView.frame
if containerView.superview != nil, containerView.frame.minY > .ulpOfOne {
let statusBarOffset = statusBarFrame.height - rect.minY
rect.origin.y = statusBarOffset
rect.size.height -= statusBarOffset
}
return rect
}
func transition(to: UIViewController, from: UIViewController, alpha: CGFloat, statusBarAlpha: CGFloat, scale: CGFloat, translate: CGFloat) {
containerViewWillLayoutSubviews()
to.view.transform = .identity
to.view.alpha = 1
let x = (leftSide ? 1 : -1) * config.menuWidth * translate
from.view.alpha = alpha
from.view.transform = CGAffineTransform
.identity
.translatedBy(x: x, y: 0)
.scaledBy(x: scale, y: scale)
statusBarView?.alpha = statusBarAlpha
}
func layerViews() {
guard let presentedViewController = presentedViewController,
let presentingViewController = presentingViewController
else { return }
statusBarView?.layer.zPosition = 2
if config.presentationStyle.menuOnTop {
addShadow(to: presentedViewController.view)
presentedViewController.view.layer.zPosition = 1
} else {
addShadow(to: presentingViewController.view)
presentedViewController.view.layer.zPosition = -1
}
}
func addShadow(to view: UIView) {
view.layer.shadowColor = config.presentationStyle.onTopShadowColor.cgColor
view.layer.shadowRadius = config.presentationStyle.onTopShadowRadius
view.layer.shadowOpacity = config.presentationStyle.onTopShadowOpacity
view.layer.shadowOffset = config.presentationStyle.onTopShadowOffset
clipsToBounds = clipsToBounds ?? view.clipsToBounds
view.clipsToBounds = false
}
func addParallax(to view: UIView) {
var effects: [UIInterpolatingMotionEffect] = []
let x = config.presentationStyle.presentingParallaxStrength.width
if x > 0 {
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
horizontal.minimumRelativeValue = -x
horizontal.maximumRelativeValue = x
effects.append(horizontal)
}
let y = config.presentationStyle.presentingParallaxStrength.height
if y > 0 {
let vertical = UIInterpolatingMotionEffect(keyPath: "center.y", type: .tiltAlongVerticalAxis)
vertical.minimumRelativeValue = -y
vertical.maximumRelativeValue = y
effects.append(vertical)
}
if effects.count > 0 {
let group = UIMotionEffectGroup()
group.motionEffects = effects
view.motionEffects.removeAll()
view.addMotionEffect(group)
}
}
func removeStyles(from view: UIView) {
view.motionEffects.removeAll()
view.layer.shadowOpacity = 0
view.layer.shadowOpacity = 0
view.clipsToBounds = clipsToBounds ?? true
clipsToBounds = false
}
}
+112
View File
@@ -0,0 +1,112 @@
//
// SideMenuPresentStyle.swift
// SideMenu
//
// Created by Jon Kent on 7/2/19.
//
import UIKit
@objcMembers
open class SideMenuPresentationStyle: InitializableClass {
/// Background color behind the views and status bar color
open var backgroundColor: UIColor = .black
/// The starting alpha value of the menu before it appears
open var menuStartAlpha: CGFloat = 1
/// Whether or not the menu is on top. If false, the presenting view is on top. Shadows are applied to the view on top.
open var menuOnTop: Bool = false
/// The amount the menu is translated along the x-axis. Zero is stationary, negative values are off-screen, positive values are on screen.
open var menuTranslateFactor: CGFloat = 0
/// The amount the menu is scaled. Less than one shrinks the view, larger than one grows the view.
open var menuScaleFactor: CGFloat = 1
/// The color of the shadow applied to the top most view.
open var onTopShadowColor: UIColor = .black
/// The radius of the shadow applied to the top most view.
open var onTopShadowRadius: CGFloat = 5
/// The opacity of the shadow applied to the top most view.
open var onTopShadowOpacity: Float = 0
/// The offset of the shadow applied to the top most view.
open var onTopShadowOffset: CGSize = .zero
/// The ending alpha of the presenting view when the menu is fully displayed.
open var presentingEndAlpha: CGFloat = 1
/// The amount the presenting view is translated along the x-axis. Zero is stationary, negative values are off-screen, positive values are on screen.
open var presentingTranslateFactor: CGFloat = 0
/// The amount the presenting view is scaled. Less than one shrinks the view, larger than one grows the view.
open var presentingScaleFactor: CGFloat = 1
/// The strength of the parallax effect on the presenting view once the menu is displayed.
open var presentingParallaxStrength: CGSize = .zero
required public init() {}
/// This method is called just before the presentation transition begins. Use this to setup any animations. The super method does not need to be called.
open func presentationTransitionWillBegin(to presentedViewController: UIViewController, from presentingViewController: UIViewController) {}
/// This method is called during the presentation animation. Use this to animate anything alongside the menu animation. The super method does not need to be called.
open func presentationTransition(to presentedViewController: UIViewController, from presentingViewController: UIViewController) {}
/// This method is called when the presentation transition ends. Use this to finish any animations. The super method does not need to be called.
open func presentationTransitionDidEnd(to presentedViewController: UIViewController, from presentingViewController: UIViewController, _ completed: Bool) {}
/// This method is called just before the dismissal transition begins. Use this to setup any animations. The super method does not need to be called.
open func dismissalTransitionWillBegin(to presentedViewController: UIViewController, from presentingViewController: UIViewController) {}
/// This method is called during the dismissal animation. Use this to animate anything alongside the menu animation. The super method does not need to be called.
open func dismissalTransition(to presentedViewController: UIViewController, from presentingViewController: UIViewController) {}
/// This method is called when the dismissal transition ends. Use this to finish any animations. The super method does not need to be called.
open func dismissalTransitionDidEnd(to presentedViewController: UIViewController, from presentingViewController: UIViewController, _ completed: Bool) {}
}
public extension SideMenuPresentationStyle {
/// Menu slides in over the existing view.
static var menuSlideIn: SideMenuPresentationStyle {
return SideMenuPresentationStyle {
$0.menuOnTop = true
$0.menuTranslateFactor = -1
}
}
/// The existing view slides out to reveal the menu underneath.
static var viewSlideOut: SideMenuPresentationStyle {
return SideMenuPresentationStyle {
$0.presentingTranslateFactor = 1
}
}
/// The existing view slides out while the menu slides in.
static var viewSlideOutMenuIn: SideMenuPresentationStyle {
return SideMenuPresentationStyle {
$0.menuTranslateFactor = -1
$0.presentingTranslateFactor = 1
}
}
/// The menu dissolves in over the existing view.
static var menuDissolveIn: SideMenuPresentationStyle {
return SideMenuPresentationStyle {
$0.menuStartAlpha = 0
$0.menuOnTop = true
}
}
/// The existing view slides out while the menu partially slides in.
static var viewSlideOutMenuPartialIn: SideMenuPresentationStyle {
return SideMenuPresentationStyle {
$0.menuTranslateFactor = -0.5
$0.presentingTranslateFactor = 1
}
}
/// The existing view slides out while the menu slides out from under it.
static var viewSlideOutMenuOut: SideMenuPresentationStyle {
return SideMenuPresentationStyle {
$0.menuTranslateFactor = 1
$0.presentingTranslateFactor = 1
}
}
/// The existing view slides out while the menu partially slides out from under it.
static var viewSlideOutMenuPartialOut: SideMenuPresentationStyle {
return SideMenuPresentationStyle {
$0.menuTranslateFactor = 0.5
$0.presentingTranslateFactor = 1
}
}
/// The existing view slides out and shrinks to reveal the menu underneath.
static var viewSlideOutMenuZoom: SideMenuPresentationStyle {
return SideMenuPresentationStyle {
$0.presentingTranslateFactor = 1
$0.menuScaleFactor = 0.95
$0.menuOnTop = true
}
}
}
+107
View File
@@ -0,0 +1,107 @@
//
// PushCoordinator.swift
// SideMenu
//
// Created by Jon Kent on 9/4/19.
//
import UIKit
protocol CoordinatorModel {
var animated: Bool { get }
var fromViewController: UIViewController { get }
var toViewController: UIViewController { get }
}
protocol Coordinator {
associatedtype Model: CoordinatorModel
init(config: Model)
@discardableResult func start() -> Bool
}
internal final class SideMenuPushCoordinator: Coordinator {
struct Model: CoordinatorModel {
var allowPushOfSameClassTwice: Bool
var alongsideTransition: (() -> Void)?
var animated: Bool
var fromViewController: UIViewController
var pushStyle: SideMenuPushStyle
var toViewController: UIViewController
}
private let config: Model
init(config: Model) {
self.config = config
}
@discardableResult func start() -> Bool {
guard config.pushStyle != .subMenu,
let fromNavigationController = config.fromViewController as? UINavigationController else {
return false
}
let toViewController = config.toViewController
let presentingViewController = fromNavigationController.presentingViewController
let splitViewController = presentingViewController as? UISplitViewController
let tabBarController = presentingViewController as? UITabBarController
let potentialNavigationController = (splitViewController?.viewControllers.first ?? tabBarController?.selectedViewController) ?? presentingViewController
guard let navigationController = potentialNavigationController as? UINavigationController else {
Print.warning(.cannotPush, arguments: String(describing: potentialNavigationController.self), required: true)
return false
}
// To avoid overlapping dismiss & pop/push calls, create a transaction block where the menu
// is dismissed after showing the appropriate screen
CATransaction.begin()
defer { CATransaction.commit() }
UIView.animationsEnabled { [weak self] in
self?.config.alongsideTransition?()
}
if let lastViewController = navigationController.viewControllers.last,
!config.allowPushOfSameClassTwice && type(of: lastViewController) == type(of: toViewController) {
return false
}
toViewController.navigationItem.hidesBackButton = config.pushStyle.hidesBackButton
switch config.pushStyle {
case .default:
navigationController.pushViewController(toViewController, animated: config.animated)
return true
// subMenu handled earlier
case .subMenu:
return false
case .popWhenPossible:
for subViewController in navigationController.viewControllers.reversed() {
if type(of: subViewController) == type(of: toViewController) {
navigationController.popToViewController(subViewController, animated: config.animated)
return true
}
}
navigationController.pushViewController(toViewController, animated: config.animated)
return true
case .preserve, .preserveAndHideBackButton:
var viewControllers = navigationController.viewControllers
let filtered = viewControllers.filter { preservedViewController in type(of: preservedViewController) == type(of: toViewController) }
guard let preservedViewController = filtered.last else {
navigationController.pushViewController(toViewController, animated: config.animated)
return true
}
viewControllers = viewControllers.filter { subViewController in subViewController !== preservedViewController }
viewControllers.append(preservedViewController)
navigationController.setViewControllers(viewControllers, animated: config.animated)
return true
case .replace:
navigationController.setViewControllers([toViewController], animated: config.animated)
return true
}
}
}
-556
View File
@@ -1,556 +0,0 @@
//
// SideMenuTransition.swift
// Pods
//
// Created by Jon Kent on 1/14/16.
//
//
import UIKit
open class SideMenuTransition: UIPercentDrivenInteractiveTransition {
fileprivate var presenting = false
fileprivate var interactive = false
fileprivate static weak var originalSuperview: UIView?
fileprivate static weak var activeGesture: UIGestureRecognizer?
fileprivate static var switchMenus = false
internal static let singleton = SideMenuTransition()
internal static var presentDirection: UIRectEdge = .left
internal static weak var tapView: UIView? {
didSet {
guard let tapView = tapView else {
return
}
tapView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
let exitPanGesture = UIPanGestureRecognizer()
exitPanGesture.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handleHideMenuPan(_:)))
let exitTapGesture = UITapGestureRecognizer()
exitTapGesture.addTarget(SideMenuTransition.self, action: #selector(SideMenuTransition.handleHideMenuTap(_:)))
tapView.addGestureRecognizer(exitPanGesture)
tapView.addGestureRecognizer(exitTapGesture)
}
}
internal static weak var statusBarView: UIView? {
didSet {
guard let statusBarView = statusBarView else {
return
}
if let menuShrinkBackgroundColor = SideMenuManager.menuAnimationBackgroundColor {
statusBarView.backgroundColor = menuShrinkBackgroundColor
} else {
statusBarView.backgroundColor = UIColor.black
}
statusBarView.isUserInteractionEnabled = false
}
}
// prevent instantiation
fileprivate override init() {
super.init()
NotificationCenter.default.addObserver(self, selector:#selector(SideMenuTransition.handleNotification), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil)
NotificationCenter.default.addObserver(self, selector:#selector(SideMenuTransition.handleNotification), name: NSNotification.Name.UIApplicationWillChangeStatusBarFrame, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(SideMenuTransition.singleton)
}
fileprivate class var presentingViewControllerForMenu: UIViewController? {
get {
return SideMenuManager.menuLeftNavigationController?.presentingViewController ?? SideMenuManager.menuRightNavigationController?.presentingViewController
}
}
fileprivate class var viewControllerForMenu: UISideMenuNavigationController? {
get {
return SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController : SideMenuManager.menuRightNavigationController
}
}
fileprivate class var visibleViewController: UIViewController? {
get {
return getVisibleViewControllerFromViewController(UIApplication.shared.keyWindow?.rootViewController)
}
}
fileprivate class func getVisibleViewControllerFromViewController(_ viewController: UIViewController?) -> UIViewController? {
if let navigationController = viewController as? UINavigationController {
return getVisibleViewControllerFromViewController(navigationController.visibleViewController)
} else if let tabBarController = viewController as? UITabBarController {
return getVisibleViewControllerFromViewController(tabBarController.selectedViewController)
} else if let presentedViewController = viewController?.presentedViewController {
return getVisibleViewControllerFromViewController(presentedViewController)
}
return viewController
}
internal class func handlePresentMenuLeftScreenEdge(_ edge: UIScreenEdgePanGestureRecognizer) {
SideMenuTransition.presentDirection = .left
handlePresentMenuPan(edge)
}
internal class func handlePresentMenuRightScreenEdge(_ edge: UIScreenEdgePanGestureRecognizer) {
SideMenuTransition.presentDirection = .right
handlePresentMenuPan(edge)
}
internal class func handlePresentMenuPan(_ pan: UIPanGestureRecognizer) {
if activeGesture == nil {
activeGesture = pan
} else if pan != activeGesture {
pan.isEnabled = false
pan.isEnabled = true
return
}
// how much distance have we panned in reference to the parent view?
guard let view = presentingViewControllerForMenu?.view ?? pan.view else {
return
}
let transform = view.transform
view.transform = .identity
let translation = pan.translation(in: pan.view!)
view.transform = transform
// do some math to translate this to a percentage based value
if !singleton.interactive {
if translation.x == 0 {
return // not sure which way the user is swiping yet, so do nothing
}
if !(pan is UIScreenEdgePanGestureRecognizer) {
SideMenuTransition.presentDirection = translation.x > 0 ? .left : .right
}
if let menuViewController = viewControllerForMenu, let visibleViewController = visibleViewController {
singleton.interactive = true
visibleViewController.present(menuViewController, animated: true, completion: nil)
} else {
return
}
}
let direction: CGFloat = SideMenuTransition.presentDirection == .left ? 1 : -1
let distance = translation.x / SideMenuManager.menuWidth
// now lets deal with different states that the gesture recognizer sends
switch (pan.state) {
case .began, .changed:
if pan is UIScreenEdgePanGestureRecognizer {
singleton.update(min(distance * direction, 1))
} else if distance > 0 && SideMenuTransition.presentDirection == .right && SideMenuManager.menuLeftNavigationController != nil {
SideMenuTransition.presentDirection = .left
switchMenus = true
singleton.cancel()
} else if distance < 0 && SideMenuTransition.presentDirection == .left && SideMenuManager.menuRightNavigationController != nil {
SideMenuTransition.presentDirection = .right
switchMenus = true
singleton.cancel()
} else {
singleton.update(min(distance * direction, 1))
}
default:
singleton.interactive = false
view.transform = .identity
let velocity = pan.velocity(in: pan.view!).x * direction
view.transform = transform
if velocity >= 100 || velocity >= -50 && abs(distance) >= 0.5 {
// bug workaround: animation briefly resets after call to finishInteractiveTransition() but before animateTransition completion is called.
if ProcessInfo().operatingSystemVersion.majorVersion == 8 && singleton.percentComplete > 1 - CGFloat.ulpOfOne {
singleton.update(0.9999)
}
singleton.finish()
activeGesture = nil
} else {
singleton.cancel()
activeGesture = nil
}
}
}
internal class func handleHideMenuPan(_ pan: UIPanGestureRecognizer) {
if activeGesture == nil {
activeGesture = pan
} else if pan != activeGesture {
pan.isEnabled = false
pan.isEnabled = true
return
}
let translation = pan.translation(in: pan.view!)
let direction:CGFloat = SideMenuTransition.presentDirection == .left ? -1 : 1
let distance = translation.x / SideMenuManager.menuWidth * direction
switch (pan.state) {
case .began:
singleton.interactive = true
presentingViewControllerForMenu?.dismiss(animated: true, completion: nil)
case .changed:
singleton.update(max(min(distance, 1), 0))
default:
singleton.interactive = false
let velocity = pan.velocity(in: pan.view!).x * direction
if velocity >= 100 || velocity >= -50 && distance >= 0.5 {
// bug workaround: animation briefly resets after call to finishInteractiveTransition() but before animateTransition completion is called.
if ProcessInfo().operatingSystemVersion.majorVersion == 8 && singleton.percentComplete > 1 - CGFloat.ulpOfOne {
singleton.update(0.9999)
}
singleton.finish()
activeGesture = nil
} else {
singleton.cancel()
activeGesture = nil
}
}
}
internal class func handleHideMenuTap(_ tap: UITapGestureRecognizer) {
presentingViewControllerForMenu?.dismiss(animated: true, completion: nil)
}
internal class func hideMenuStart() {
guard let mainViewController = presentingViewControllerForMenu,
let menuView = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController?.view : SideMenuManager.menuRightNavigationController?.view else {
return
}
mainViewController.view.transform = .identity
mainViewController.view.alpha = 1
mainViewController.view.frame.origin.y = 0
menuView.transform = .identity
menuView.frame.origin.y = 0
menuView.frame.size.width = SideMenuManager.menuWidth
menuView.frame.size.height = mainViewController.view.frame.height // in case status bar height changed
var statusBarFrame = UIApplication.shared.statusBarFrame
let statusBarOffset = SideMenuManager.appScreenRect.size.height - mainViewController.view.frame.maxY
// For in-call status bar, height is normally 40, which overlaps view. Instead, calculate height difference
// of view and set height to fill in remaining space.
if statusBarOffset >= CGFloat.ulpOfOne {
statusBarFrame.size.height = statusBarOffset
}
SideMenuTransition.statusBarView?.frame = statusBarFrame
SideMenuTransition.statusBarView?.alpha = 0
switch SideMenuManager.menuPresentMode {
case .viewSlideOut:
menuView.alpha = 1 - SideMenuManager.menuAnimationFadeStrength
menuView.frame.origin.x = SideMenuTransition.presentDirection == .left ? 0 : mainViewController.view.frame.width - SideMenuManager.menuWidth
mainViewController.view.frame.origin.x = 0
menuView.transform = CGAffineTransform(scaleX: SideMenuManager.menuAnimationTransformScaleFactor, y: SideMenuManager.menuAnimationTransformScaleFactor)
case .viewSlideInOut:
menuView.alpha = 1
menuView.frame.origin.x = SideMenuTransition.presentDirection == .left ? -menuView.frame.width : mainViewController.view.frame.width
mainViewController.view.frame.origin.x = 0
case .menuSlideIn:
menuView.alpha = 1
menuView.frame.origin.x = SideMenuTransition.presentDirection == .left ? -menuView.frame.width : mainViewController.view.frame.width
case .menuDissolveIn:
menuView.alpha = 0
menuView.frame.origin.x = SideMenuTransition.presentDirection == .left ? 0 : mainViewController.view.frame.width - SideMenuManager.menuWidth
mainViewController.view.frame.origin.x = 0
}
}
internal class func hideMenuComplete() {
guard let mainViewController = presentingViewControllerForMenu,
let menuView = viewControllerForMenu?.view else {
return
}
SideMenuTransition.tapView?.removeFromSuperview()
SideMenuTransition.statusBarView?.removeFromSuperview()
mainViewController.view.motionEffects.removeAll()
mainViewController.view.layer.shadowOpacity = 0
menuView.layer.shadowOpacity = 0
if let topNavigationController = mainViewController as? UINavigationController {
topNavigationController.interactivePopGestureRecognizer!.isEnabled = true
}
if let originalSuperview = originalSuperview {
originalSuperview.addSubview(mainViewController.view)
let y = originalSuperview.bounds.height - mainViewController.view.frame.size.height
mainViewController.view.frame.origin.y = max(y, 0)
}
}
internal class func presentMenuStart() {
guard let menuView = viewControllerForMenu?.view,
let mainViewController = presentingViewControllerForMenu else {
return
}
menuView.alpha = 1
menuView.transform = .identity
menuView.frame.size.width = SideMenuManager.menuWidth
let size = SideMenuManager.appScreenRect.size
menuView.frame.origin.x = SideMenuTransition.presentDirection == .left ? 0 : size.width - SideMenuManager.menuWidth
mainViewController.view.transform = .identity
mainViewController.view.frame.size.width = size.width
let statusBarOffset = size.height - menuView.bounds.height
mainViewController.view.bounds.size.height = size.height - max(statusBarOffset, 0)
mainViewController.view.frame.origin.y = 0
var statusBarFrame = UIApplication.shared.statusBarFrame
// For in-call status bar, height is normally 40, which overlaps view. Instead, calculate height difference
// of view and set height to fill in remaining space.
if statusBarOffset >= CGFloat.ulpOfOne {
statusBarFrame.size.height = statusBarOffset
}
SideMenuTransition.statusBarView?.frame = statusBarFrame
SideMenuTransition.statusBarView?.alpha = 1
switch SideMenuManager.menuPresentMode {
case .viewSlideOut, .viewSlideInOut:
mainViewController.view.layer.shadowColor = SideMenuManager.menuShadowColor.cgColor
mainViewController.view.layer.shadowRadius = SideMenuManager.menuShadowRadius
mainViewController.view.layer.shadowOpacity = SideMenuManager.menuShadowOpacity
mainViewController.view.layer.shadowOffset = CGSize(width: 0, height: 0)
let direction:CGFloat = SideMenuTransition.presentDirection == .left ? 1 : -1
mainViewController.view.frame.origin.x = direction * (menuView.frame.width)
case .menuSlideIn, .menuDissolveIn:
if SideMenuManager.menuBlurEffectStyle == nil {
menuView.layer.shadowColor = SideMenuManager.menuShadowColor.cgColor
menuView.layer.shadowRadius = SideMenuManager.menuShadowRadius
menuView.layer.shadowOpacity = SideMenuManager.menuShadowOpacity
menuView.layer.shadowOffset = CGSize(width: 0, height: 0)
}
mainViewController.view.frame.origin.x = 0
}
if SideMenuManager.menuPresentMode != .viewSlideOut {
mainViewController.view.transform = CGAffineTransform(scaleX: SideMenuManager.menuAnimationTransformScaleFactor, y: SideMenuManager.menuAnimationTransformScaleFactor)
mainViewController.view.alpha = 1 - SideMenuManager.menuAnimationFadeStrength
}
}
internal class func presentMenuComplete() {
guard let mainViewController = presentingViewControllerForMenu else {
return
}
switch SideMenuManager.menuPresentMode {
case .menuSlideIn, .menuDissolveIn, .viewSlideInOut:
if SideMenuManager.menuParallaxStrength != 0 {
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
horizontal.minimumRelativeValue = -SideMenuManager.menuParallaxStrength
horizontal.maximumRelativeValue = SideMenuManager.menuParallaxStrength
let vertical = UIInterpolatingMotionEffect(keyPath: "center.y", type: .tiltAlongVerticalAxis)
vertical.minimumRelativeValue = -SideMenuManager.menuParallaxStrength
vertical.maximumRelativeValue = SideMenuManager.menuParallaxStrength
let group = UIMotionEffectGroup()
group.motionEffects = [horizontal, vertical]
mainViewController.view.addMotionEffect(group)
}
case .viewSlideOut: break;
}
if let topNavigationController = mainViewController as? UINavigationController {
topNavigationController.interactivePopGestureRecognizer!.isEnabled = false
}
}
internal func handleNotification() {
guard let mainViewController = SideMenuTransition.presentingViewControllerForMenu,
let menuViewController = SideMenuTransition.viewControllerForMenu,
menuViewController.presentedViewController == nil && menuViewController.presentingViewController != nil else {
return
}
if let originalSuperview = SideMenuTransition.originalSuperview {
originalSuperview.addSubview(mainViewController.view)
}
UIView.animate(withDuration: SideMenuManager.menuAnimationDismissDuration,
delay: 0,
usingSpringWithDamping: SideMenuManager.menuAnimationUsingSpringWithDamping,
initialSpringVelocity: SideMenuManager.menuAnimationInitialSpringVelocity,
options: SideMenuManager.menuAnimationOptions,
animations: {
SideMenuTransition.hideMenuStart()
}) { (finished) -> Void in
SideMenuTransition.hideMenuComplete()
menuViewController.dismiss(animated: false, completion: nil)
}
}
}
extension SideMenuTransition: UIViewControllerAnimatedTransitioning {
// animate a change from one viewcontroller to another
open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// get reference to our fromView, toView and the container view that we should perform the transition in
let container = transitionContext.containerView
// prevent any other menu gestures from firing
container.isUserInteractionEnabled = false
if let menuBackgroundColor = SideMenuManager.menuAnimationBackgroundColor {
container.backgroundColor = menuBackgroundColor
}
let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
// assign references to our menu view controller and the 'bottom' view controller from the tuple
// remember that our menuViewController will alternate between the from and to view controller depending if we're presenting or dismissing
let menuViewController = presenting ? toViewController : fromViewController
let topViewController = presenting ? fromViewController : toViewController
let menuView = menuViewController.view!
let topView = topViewController.view!
// prepare menu items to slide in
if presenting {
SideMenuTransition.originalSuperview = topView.superview
// add the both views to our view controller
switch SideMenuManager.menuPresentMode {
case .viewSlideOut, .viewSlideInOut:
container.addSubview(menuView)
container.addSubview(topView)
case .menuSlideIn, .menuDissolveIn:
container.addSubview(topView)
container.addSubview(menuView)
}
if SideMenuManager.menuFadeStatusBar {
let statusBarView = UIView()
SideMenuTransition.statusBarView = statusBarView
container.addSubview(statusBarView)
}
SideMenuTransition.hideMenuStart()
}
let animate = {
if self.presenting {
SideMenuTransition.presentMenuStart()
} else {
SideMenuTransition.hideMenuStart()
}
}
let complete = {
container.isUserInteractionEnabled = true
// tell our transitionContext object that we've finished animating
if transitionContext.transitionWasCancelled {
let viewControllerForPresentedMenu = SideMenuTransition.presentingViewControllerForMenu
if self.presenting {
SideMenuTransition.hideMenuComplete()
} else {
SideMenuTransition.presentMenuComplete()
}
transitionContext.completeTransition(false)
if SideMenuTransition.switchMenus {
SideMenuTransition.switchMenus = false
viewControllerForPresentedMenu?.present(SideMenuTransition.viewControllerForMenu!, animated: true, completion: nil)
}
return
}
if self.presenting {
SideMenuTransition.presentMenuComplete()
transitionContext.completeTransition(true)
switch SideMenuManager.menuPresentMode {
case .viewSlideOut, .viewSlideInOut:
container.addSubview(topView)
case .menuSlideIn, .menuDissolveIn:
container.insertSubview(topView, at: 0)
}
if !SideMenuManager.menuPresentingViewControllerUserInteractionEnabled {
let tapView = UIView()
container.insertSubview(tapView, aboveSubview: topView)
tapView.bounds = container.bounds
tapView.center = topView.center
SideMenuTransition.tapView = tapView
}
if let statusBarView = SideMenuTransition.statusBarView {
container.bringSubview(toFront: statusBarView)
}
return
}
SideMenuTransition.hideMenuComplete()
transitionContext.completeTransition(true)
menuView.removeFromSuperview()
}
// perform the animation!
let duration = transitionDuration(using: transitionContext)
if interactive {
UIView.animate(withDuration: duration,
delay: 0,
options: .curveLinear,
animations: {
animate()
}, completion: { (finished) in
complete()
})
} else {
UIView.animate(withDuration: duration,
delay: 0,
usingSpringWithDamping: SideMenuManager.menuAnimationUsingSpringWithDamping,
initialSpringVelocity: SideMenuManager.menuAnimationInitialSpringVelocity,
options: SideMenuManager.menuAnimationOptions,
animations: {
animate()
}) { (finished) -> Void in
complete()
}
}
}
// return how many seconds the transiton animation will take
open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
if interactive {
return SideMenuManager.menuAnimationCompleteGestureDuration
}
return presenting ? SideMenuManager.menuAnimationPresentDuration : SideMenuManager.menuAnimationDismissDuration
}
}
extension SideMenuTransition: UIViewControllerTransitioningDelegate {
// return the animator when presenting a viewcontroller
// rememeber that an animator (or animation controller) is any object that aheres to the UIViewControllerAnimatedTransitioning protocol
open func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
self.presenting = true
SideMenuTransition.presentDirection = presented == SideMenuManager.menuLeftNavigationController ? .left : .right
return self
}
// return the animator used when dismissing from a viewcontroller
open func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
presenting = false
return self
}
open func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
// if our interactive flag is true, return the transition manager object
// otherwise return nil
return interactive ? SideMenuTransition.singleton : nil
}
open func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactive ? SideMenuTransition.singleton : nil
}
}
@@ -0,0 +1,93 @@
//
// SideMenuTransitioningDelegate.swift
// SideMenu
//
// Created by Jon Kent on 8/29/19.
// Copyright © 2019 jonkykong. All rights reserved.
//
import UIKit
internal protocol SideMenuTransitionControllerDelegate: class {
func sideMenuTransitionController(_ transitionController: SideMenuTransitionController, didDismiss viewController: UIViewController)
func sideMenuTransitionController(_ transitionController: SideMenuTransitionController, didPresent viewController: UIViewController)
}
internal final class SideMenuTransitionController: NSObject, UIViewControllerTransitioningDelegate {
typealias Model = MenuModel & AnimationModel & PresentationModel
private let leftSide: Bool
private let config: Model
private var animationController: SideMenuAnimationController?
private weak var interactionController: SideMenuInteractionController?
var interactive: Bool = false
weak var delegate: SideMenuTransitionControllerDelegate?
init(leftSide: Bool, config: Model) {
self.leftSide = leftSide
self.config = config
super.init()
}
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
animationController = SideMenuAnimationController(
config: config,
leftSide: leftSide,
delegate: self)
return animationController
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return animationController
}
func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactionController(using: animator)
}
func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactionController(using: animator)
}
internal func handle(state: SideMenuInteractionController.State) {
interactionController?.handle(state: state)
}
func layout() {
animationController?.layout()
}
func transition(presenting: Bool, animated: Bool = true, interactive: Bool = false, alongsideTransition: (() -> Void)? = nil, complete: Bool = true, completion: ((Bool) -> Void)? = nil) {
animationController?.transition(
presenting: presenting,
animated: animated,
interactive: interactive,
alongsideTransition: alongsideTransition,
complete: complete, completion: completion
)
}
}
extension SideMenuTransitionController: SideMenuAnimationControllerDelegate {
internal func sideMenuAnimationController(_ animationController: SideMenuAnimationController, didDismiss viewController: UIViewController) {
delegate?.sideMenuTransitionController(self, didDismiss: viewController)
}
internal func sideMenuAnimationController(_ animationController: SideMenuAnimationController, didPresent viewController: UIViewController) {
delegate?.sideMenuTransitionController(self, didPresent: viewController)
}
}
private extension SideMenuTransitionController {
func interactionController(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
guard interactive else { return nil }
interactive = false
let interactionController = SideMenuInteractionController(cancelWhenBackgrounded: config.dismissWhenBackgrounded, completionCurve: config.completionCurve)
self.interactionController = interactionController
return interactionController
}
}
@@ -1,182 +0,0 @@
//
// UISideMenuNavigationController.swift
//
// Created by Jon Kent on 1/14/16.
// Copyright © 2016 Jon Kent. All rights reserved.
//
import UIKit
open class UISideMenuNavigationController: UINavigationController {
internal var originalMenuBackgroundColor: UIColor?
open override func awakeFromNib() {
super.awakeFromNib()
// if this isn't set here, segues cause viewWillAppear and viewDidAppear to be called twice
// likely because the transition completes and the presentingViewController is added back
// into view for the default transition style.
modalPresentationStyle = .overFullScreen
}
/// Whether the menu appears on the right or left side of the screen. Right is the default.
@IBInspectable open var leftSide: Bool = false {
didSet {
if isViewLoaded && oldValue != leftSide { // suppress warnings
didSetSide()
}
}
}
override open func viewDidLoad() {
super.viewDidLoad()
didSetSide()
}
open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Dismiss keyboard to prevent weird keyboard animations from occurring during transition
presentingViewController?.view.endEditing(true)
}
fileprivate func didSetSide() {
if leftSide {
SideMenuManager.menuLeftNavigationController = self
} else {
SideMenuManager.menuRightNavigationController = self
}
}
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// We had presented a view before, so lets dismiss ourselves as already acted upon
if view.isHidden {
SideMenuTransition.hideMenuComplete()
dismiss(animated: false, completion: { () -> Void in
self.view.isHidden = false
})
}
if topViewController == nil {
print("SideMenu Warning: the menu doesn't have a view controller to show! UISideMenuNavigationController needs a view controller to display just like a UINavigationController.")
}
}
override open func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// We're presenting a view controller from the menu, so we need to hide the menu so it isn't showing when the presented view is dismissed.
if !isBeingDismissed {
view.isHidden = true
SideMenuTransition.hideMenuStart()
}
}
override open func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
// Don't bother resizing if the view isn't visible
guard !view.isHidden else {
return
}
NotificationCenter.default.removeObserver(SideMenuTransition.singleton, name: NSNotification.Name.UIApplicationWillChangeStatusBarFrame, object: nil)
coordinator.animate(alongsideTransition: { (context) in
SideMenuTransition.presentMenuStart()
}) { (context) in
NotificationCenter.default.addObserver(SideMenuTransition.singleton, selector:#selector(SideMenuTransition.handleNotification), name: NSNotification.Name.UIApplicationWillChangeStatusBarFrame, object: nil)
}
}
override open func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let presentingViewController = presentingViewController {
presentingViewController.prepare(for: segue, sender: sender)
}
}
override open func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if let presentingViewController = presentingViewController {
return presentingViewController.shouldPerformSegue(withIdentifier: identifier, sender: sender)
}
return super.shouldPerformSegue(withIdentifier: identifier, sender: sender)
}
override open func pushViewController(_ viewController: UIViewController, animated: Bool) {
guard viewControllers.count > 0 && SideMenuManager.menuPushStyle != .subMenu else {
// NOTE: pushViewController is called by init(rootViewController: UIViewController)
// so we must perform the normal super method in this case.
super.pushViewController(viewController, animated: animated)
return
}
let tabBarController = presentingViewController as? UITabBarController
guard let navigationController = (tabBarController?.selectedViewController ?? presentingViewController) as? UINavigationController else {
print("SideMenu Warning: attempt to push a View Controller from \(String(describing: presentingViewController.self)) where its navigationController == nil. It must be embedded in a Navigation Controller for this to work.")
return
}
// To avoid overlapping dismiss & pop/push calls, create a transaction block where the menu
// is dismissed after showing the appropriate screen
CATransaction.begin()
CATransaction.setCompletionBlock( { () -> Void in
self.dismiss(animated: true, completion: nil)
self.visibleViewController?.viewWillAppear(false) // Hack: force selection to get cleared on UITableViewControllers when reappearing using custom transitions
})
let areAnimationsEnabled = UIView.areAnimationsEnabled
UIView.setAnimationsEnabled(true)
UIView.animate(withDuration: SideMenuManager.menuAnimationDismissDuration, animations: { () -> Void in
SideMenuTransition.hideMenuStart()
})
UIView.setAnimationsEnabled(areAnimationsEnabled)
if let lastViewController = navigationController.viewControllers.last, !SideMenuManager.menuAllowPushOfSameClassTwice && type(of: lastViewController) == type(of: viewController) {
CATransaction.commit()
return
}
switch SideMenuManager.menuPushStyle {
case .subMenu, .defaultBehavior: break // .subMenu handled earlier, .defaultBehavior falls through to end
case .popWhenPossible:
for subViewController in navigationController.viewControllers.reversed() {
if type(of: subViewController) == type(of: viewController) {
navigationController.popToViewController(subViewController, animated: animated)
CATransaction.commit()
return
}
}
case .preserve, .preserveAndHideBackButton:
var viewControllers = navigationController.viewControllers
let filtered = viewControllers.filter { preservedViewController in type(of: preservedViewController) == type(of: viewController) }
if let preservedViewController = filtered.last {
viewControllers = viewControllers.filter { subViewController in subViewController !== preservedViewController }
if SideMenuManager.menuPushStyle == .preserveAndHideBackButton {
preservedViewController.navigationItem.hidesBackButton = true
}
viewControllers.append(preservedViewController)
navigationController.setViewControllers(viewControllers, animated: animated)
CATransaction.commit()
return
}
if SideMenuManager.menuPushStyle == .preserveAndHideBackButton {
viewController.navigationItem.hidesBackButton = true
}
case .replace:
viewController.navigationItem.hidesBackButton = true
navigationController.setViewControllers([viewController], animated: animated)
CATransaction.commit()
return
}
navigationController.pushViewController(viewController, animated: animated)
CATransaction.commit()
}
}
+18 -8
View File
@@ -10,9 +10,19 @@ import UIKit
open class UITableViewVibrantCell: UITableViewCell {
fileprivate var vibrancyView:UIVisualEffectView = UIVisualEffectView()
fileprivate var vibrancySelectedBackgroundView:UIVisualEffectView = UIVisualEffectView()
fileprivate var defaultSelectedBackgroundView:UIView?
private var vibrancyView: UIVisualEffectView = UIVisualEffectView()
private var vibrancySelectedBackgroundView: UIVisualEffectView = UIVisualEffectView()
private var defaultSelectedBackgroundView: UIView?
open var blurEffectStyle: UIBlurEffect.Style? {
didSet {
updateBlur()
}
}
// For registering with UITableView without subclassing otherwise dequeuing instance of the cell causes an exception
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
@@ -27,16 +37,16 @@ open class UITableViewVibrantCell: UITableViewCell {
let blurSelectionEffect = UIBlurEffect(style: .light)
vibrancySelectedBackgroundView.effect = blurSelectionEffect
defaultSelectedBackgroundView = selectedBackgroundView
updateBlur()
}
override open func layoutSubviews() {
super.layoutSubviews()
internal func updateBlur() {
// shouldn't be needed but backgroundColor is set to white on iPad:
backgroundColor = UIColor.clear
if !UIAccessibilityIsReduceTransparencyEnabled() && SideMenuManager.menuBlurEffectStyle != nil {
let blurEffect = UIBlurEffect(style: SideMenuManager.menuBlurEffectStyle!)
if let blurEffectStyle = blurEffectStyle, !UIAccessibility.isReduceTransparencyEnabled {
let blurEffect = UIBlurEffect(style: blurEffectStyle)
vibrancyView.effect = UIVibrancyEffect(blurEffect: blurEffect)
if selectedBackgroundView != nil && selectedBackgroundView != vibrancySelectedBackgroundView {
+1 -2
View File
@@ -1,8 +1,7 @@
source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!
platform :ios, '10.0'
target 'Example' do
pod "SideMenu", :path => "."
target 'ExampleTests'
end
+4 -4
View File
@@ -1,5 +1,5 @@
PODS:
- SideMenu (2.0.5)
- SideMenu (6.4.9)
DEPENDENCIES:
- SideMenu (from `.`)
@@ -9,8 +9,8 @@ EXTERNAL SOURCES:
:path: "."
SPEC CHECKSUMS:
SideMenu: 0ecfd407b24e7d36c57fc50ca7f5d7cedb7c8841
SideMenu: 8ef57a3cfc024a2d3fc1c036c7fe98537baec9e0
PODFILE CHECKSUM: 58fed701dc13a7835ed36507e7cf19fa22035003
PODFILE CHECKSUM: 863f183ea1ab6f64dc8553590349c586faf8e4a1
COCOAPODS: 1.1.1
COCOAPODS: 1.9.3
+6 -4
View File
@@ -1,6 +1,6 @@
{
"name": "SideMenu",
"version": "2.0.5",
"version": "6.4.9",
"summary": "Simple side menu control for iOS in Swift inspired by Facebook. Right and Left sides. No coding required.",
"description": "SideMenu is a simple and versatile side menu control. It's highly customizable, but can also be implemented in storyboard without a single line of code. The are three standard animation styles to choose from along with several other options for further customization if desired. Just type SideMenuManager.menu... and code completion will show you everything you can customize.",
"homepage": "https://github.com/jonkykong/SideMenu",
@@ -19,10 +19,12 @@
},
"source": {
"git": "https://github.com/jonkykong/SideMenu.git",
"tag": "2.0.5"
"tag": "6.4.9"
},
"platforms": {
"ios": "8.0"
"ios": "10.0"
},
"source_files": "Pod/Classes/**/*"
"swift_versions": "5.0",
"source_files": "Pod/Classes/**/*",
"swift_version": "5.0"
}
+4 -4
View File
@@ -1,5 +1,5 @@
PODS:
- SideMenu (2.0.5)
- SideMenu (6.4.9)
DEPENDENCIES:
- SideMenu (from `.`)
@@ -9,8 +9,8 @@ EXTERNAL SOURCES:
:path: "."
SPEC CHECKSUMS:
SideMenu: 0ecfd407b24e7d36c57fc50ca7f5d7cedb7c8841
SideMenu: 8ef57a3cfc024a2d3fc1c036c7fe98537baec9e0
PODFILE CHECKSUM: 58fed701dc13a7835ed36507e7cf19fa22035003
PODFILE CHECKSUM: 863f183ea1ab6f64dc8553590349c586faf8e4a1
COCOAPODS: 1.1.1
COCOAPODS: 1.9.3
+419 -493
View File
File diff suppressed because it is too large Load Diff
@@ -1,26 +0,0 @@
# Acknowledgements
This application makes use of the following third party libraries:
## SideMenu
Copyright (c) 2015 Jonathan Kent <contact@jonkent.me>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Generated by CocoaPods - https://cocoapods.org
@@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>FooterText</key>
<string>This application makes use of the following third party libraries:</string>
<key>Title</key>
<string>Acknowledgements</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2015 Jonathan Kent &lt;contact@jonkent.me&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>SideMenu</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - https://cocoapods.org</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Acknowledgements</string>
<key>Title</key>
<string>Acknowledgements</string>
</dict>
</plist>
@@ -1,5 +0,0 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_Pods_Example_ExampleTests : NSObject
@end
@implementation PodsDummy_Pods_Example_ExampleTests
@end
@@ -1,91 +0,0 @@
#!/bin/sh
set -e
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
install_framework()
{
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
local source="${BUILT_PRODUCTS_DIR}/$1"
elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
elif [ -r "$1" ]; then
local source="$1"
fi
local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
if [ -L "${source}" ]; then
echo "Symlinked..."
source="$(readlink "${source}")"
fi
# use filter instead of exclude so missing patterns dont' throw errors
echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
local basename
basename="$(basename -s .framework "$1")"
binary="${destination}/${basename}.framework/${basename}"
if ! [ -r "$binary" ]; then
binary="${destination}/${basename}"
fi
# Strip invalid architectures so "fat" simulator / device frameworks work on device
if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
strip_invalid_archs "$binary"
fi
# Resign the code if required by the build settings to avoid unstable apps
code_sign_if_enabled "${destination}/$(basename "$1")"
# Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
local swift_runtime_libs
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
for lib in $swift_runtime_libs; do
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
code_sign_if_enabled "${destination}/${lib}"
done
fi
}
# Signs a framework with the provided identity
code_sign_if_enabled() {
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
# Use the current code_sign_identitiy
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
fi
}
# Strip invalid architectures
strip_invalid_archs() {
binary="$1"
# Get architectures for current file
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
stripped=""
for arch in $archs; do
if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
# Strip non-valid architectures in-place
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
stripped="$stripped $arch"
fi
done
if [[ "$stripped" ]]; then
echo "Stripped $binary of architectures:$stripped"
fi
}
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework "$BUILT_PRODUCTS_DIR/SideMenu/SideMenu.framework"
fi
if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework "$BUILT_PRODUCTS_DIR/SideMenu/SideMenu.framework"
fi
@@ -1,96 +0,0 @@
#!/bin/sh
set -e
mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
> "$RESOURCES_TO_COPY"
XCASSET_FILES=()
case "${TARGETED_DEVICE_FAMILY}" in
1,2)
TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
;;
1)
TARGET_DEVICE_ARGS="--target-device iphone"
;;
2)
TARGET_DEVICE_ARGS="--target-device ipad"
;;
*)
TARGET_DEVICE_ARGS="--target-device mac"
;;
esac
install_resource()
{
if [[ "$1" = /* ]] ; then
RESOURCE_PATH="$1"
else
RESOURCE_PATH="${PODS_ROOT}/$1"
fi
if [[ ! -e "$RESOURCE_PATH" ]] ; then
cat << EOM
error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
EOM
exit 1
fi
case $RESOURCE_PATH in
*.storyboard)
echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
;;
*.xib)
echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
;;
*.framework)
echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
;;
*.xcdatamodel)
echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
;;
*.xcdatamodeld)
echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
;;
*.xcmappingmodel)
echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
;;
*.xcassets)
ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
;;
*)
echo "$RESOURCE_PATH"
echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
;;
esac
}
mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi
rm -f "$RESOURCES_TO_COPY"
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
then
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
while read line; do
if [[ $line != "${PODS_ROOT}*" ]]; then
XCASSET_FILES+=("$line")
fi
done <<<"$OTHER_XCASSETS"
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi
@@ -1,8 +0,0 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#endif
FOUNDATION_EXPORT double Pods_Example_ExampleTestsVersionNumber;
FOUNDATION_EXPORT const unsigned char Pods_Example_ExampleTestsVersionString[];
@@ -1,11 +0,0 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/SideMenu"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/SideMenu/SideMenu.framework/Headers"
OTHER_LDFLAGS = $(inherited) -framework "SideMenu"
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
PODS_BUILD_DIR = $BUILD_DIR
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}/Pods
@@ -1,6 +0,0 @@
framework module Pods_Example_ExampleTests {
umbrella header "Pods-Example-ExampleTests-umbrella.h"
export *
module * { export * }
}
@@ -1,11 +0,0 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/SideMenu"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/SideMenu/SideMenu.framework/Headers"
OTHER_LDFLAGS = $(inherited) -framework "SideMenu"
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
PODS_BUILD_DIR = $BUILD_DIR
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}/Pods
@@ -1,11 +1,33 @@
#!/bin/sh
set -e
set -u
set -o pipefail
function on_error {
echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
}
trap 'on_error $LINENO' ERR
if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
# If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
# frameworks to, so exit 0 (signalling the script phase was successful).
exit 0
fi
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
# Used as a return value for each invocation of `strip_invalid_archs` function.
STRIP_BINARY_RETVAL=0
# This protects against multiple targets copying the same framework dependency at the same time. The solution
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
# Copies and strips a vendored framework
install_framework()
{
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
@@ -19,19 +41,24 @@ install_framework()
local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
if [ -L "${source}" ]; then
echo "Symlinked..."
source="$(readlink "${source}")"
echo "Symlinked..."
source="$(readlink "${source}")"
fi
# use filter instead of exclude so missing patterns dont' throw errors
echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
# Use filter instead of exclude so missing patterns don't throw errors.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
local basename
basename="$(basename -s .framework "$1")"
binary="${destination}/${basename}.framework/${basename}"
if ! [ -r "$binary" ]; then
binary="${destination}/${basename}"
elif [ -L "${binary}" ]; then
echo "Destination binary is symlinked..."
dirname="$(dirname "${binary}")"
binary="${dirname}/$(readlink "${binary}")"
fi
# Strip invalid architectures so "fat" simulator / device frameworks work on device
@@ -45,7 +72,7 @@ install_framework()
# Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
local swift_runtime_libs
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
for lib in $swift_runtime_libs; do
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
@@ -54,38 +81,127 @@ install_framework()
fi
}
# Copies and strips a vendored dSYM
install_dsym() {
local source="$1"
warn_missing_arch=${2:-true}
if [ -r "$source" ]; then
# Copy the dSYM into the targets temp dir.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
local basename
basename="$(basename -s .dSYM "$source")"
binary_name="$(ls "$source/Contents/Resources/DWARF")"
binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
# Strip invalid architectures so "fat" simulator / device frameworks work on device
if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
strip_invalid_archs "$binary" "$warn_missing_arch"
fi
if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
# Move the stripped file into its final destination.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
else
# The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
fi
fi
}
# Copies the bcsymbolmap files of a vendored framework
install_bcsymbolmap() {
local bcsymbolmap_path="$1"
local destination="${BUILT_PRODUCTS_DIR}"
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
}
# Signs a framework with the provided identity
code_sign_if_enabled() {
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
# Use the current code_sign_identitiy
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
# Use the current code_sign_identity
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
code_sign_cmd="$code_sign_cmd &"
fi
echo "$code_sign_cmd"
eval "$code_sign_cmd"
fi
}
# Strip invalid architectures
strip_invalid_archs() {
binary="$1"
# Get architectures for current file
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
warn_missing_arch=${2:-true}
# Get architectures for current target binary
binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
# Intersect them with the architectures we are building for
intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
# If there are no archs supported by this binary then warn the user
if [[ -z "$intersected_archs" ]]; then
if [[ "$warn_missing_arch" == "true" ]]; then
echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
fi
STRIP_BINARY_RETVAL=0
return
fi
stripped=""
for arch in $archs; do
if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
for arch in $binary_archs; do
if ! [[ "${ARCHS}" == *"$arch"* ]]; then
# Strip non-valid architectures in-place
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
lipo -remove "$arch" -output "$binary" "$binary"
stripped="$stripped $arch"
fi
done
if [[ "$stripped" ]]; then
echo "Stripped $binary of architectures:$stripped"
fi
STRIP_BINARY_RETVAL=1
}
install_artifact() {
artifact="$1"
base="$(basename "$artifact")"
case $base in
*.framework)
install_framework "$artifact"
;;
*.dSYM)
# Suppress arch warnings since XCFrameworks will include many dSYM files
install_dsym "$artifact" "false"
;;
*.bcsymbolmap)
install_bcsymbolmap "$artifact"
;;
*)
echo "error: Unrecognized artifact "$artifact""
;;
esac
}
copy_artifacts() {
file_list="$1"
while read artifact; do
install_artifact "$artifact"
done <$file_list
}
ARTIFACT_LIST_FILE="${BUILT_PRODUCTS_DIR}/cocoapods-artifacts-${CONFIGURATION}.txt"
if [ -r "${ARTIFACT_LIST_FILE}" ]; then
copy_artifacts "${ARTIFACT_LIST_FILE}"
fi
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework "$BUILT_PRODUCTS_DIR/SideMenu/SideMenu.framework"
install_framework "${BUILT_PRODUCTS_DIR}/SideMenu/SideMenu.framework"
fi
if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework "$BUILT_PRODUCTS_DIR/SideMenu/SideMenu.framework"
install_framework "${BUILT_PRODUCTS_DIR}/SideMenu/SideMenu.framework"
fi
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
wait
fi
@@ -1,5 +1,13 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
@@ -1,11 +1,12 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/SideMenu"
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SideMenu"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SideMenu/SideMenu.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/SideMenu/SideMenu.framework/Headers"
OTHER_LDFLAGS = $(inherited) -framework "SideMenu"
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
PODS_BUILD_DIR = $BUILD_DIR
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
PODS_ROOT = ${SRCROOT}/Pods
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
@@ -1,11 +1,12 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/SideMenu"
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SideMenu"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SideMenu/SideMenu.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/SideMenu/SideMenu.framework/Headers"
OTHER_LDFLAGS = $(inherited) -framework "SideMenu"
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
PODS_BUILD_DIR = $BUILD_DIR
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
PODS_ROOT = ${SRCROOT}/Pods
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>6.4.9</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
+8
View File
@@ -1,4 +1,12 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
+8
View File
@@ -1,5 +1,13 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
+6 -5
View File
@@ -1,9 +1,10 @@
CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/SideMenu
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SideMenu
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
PODS_BUILD_DIR = $BUILD_DIR
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/..
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
+301 -146
View File
@@ -1,33 +1,59 @@
# ▤ SideMenu
[![Version](https://img.shields.io/cocoapods/v/SideMenu.svg?style=flat)](http://cocoapods.org/pods/SideMenu)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![License](https://img.shields.io/cocoapods/l/SideMenu.svg?style=flat)](http://cocoapods.org/pods/SideMenu)
[![Platform](https://img.shields.io/cocoapods/p/SideMenu.svg?style=flat)](http://cocoapods.org/pods/SideMenu)
[![CircleCI](https://circleci.com/gh/jonkykong/SideMenu.svg?style=svg)](https://circleci.com/gh/jonkykong/SideMenu)
[![Version](https://img.shields.io/cocoapods/v/SideMenu.svg?style=flat-square)](http://cocoapods.org/pods/SideMenu)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat-square)](https://github.com/Carthage/Carthage)
[![License](https://img.shields.io/cocoapods/l/SideMenu.svg?style=flat-square)](http://cocoapods.org/pods/SideMenu)
[![Platform](https://img.shields.io/cocoapods/p/SideMenu.svg?style=flat-square)](http://cocoapods.org/pods/SideMenu)
### If you like SideMenu, give it a ★ at the top right of its [GitHub](https://github.com/jonkykong/SideMenu) page.
#### Using SideMenu in your app? [Send](mailto:contact@jonkent.me?subject=SideMenu in action!) me a link to your app in the app store!
### If you like SideMenu, give it a ★ at the top right of this page.
#### SideMenu needs your help! If you're a skilled iOS developer and want to help maintain this repository and answer issues asked by the community, please [send me an email](mailto:yo@massappeal.co?subject=I%20Want%20To%20Help!).
> I'm Jon Kent and I freelance iOS design, development, and mobile strategies. I love coffee and play the drums. [**Hire me**](mailto:contact@jonkent.me?subject=Let's build something amazing.) to help you make cool stuff. I also have a [website](http://jonkent.me). *Note: If you're having a problem with SideMenu, please open an [issue](https://github.com/jonkykong/SideMenu/issues/new) and do not email me.*
> Hi, I'm Jon Kent and I am an iOS designer, developer, and mobile strategist. I love coffee and play the drums.
> * [**Hire me**](mailto:yo@massappeal.co?subject=Let's%20build%20something%20amazing) to help you make cool stuff. *Note: If you're having a problem with SideMenu, please open an [issue](https://github.com/jonkykong/SideMenu/issues/new) and do not email me.*
> * Check out my [website](http://massappeal.co) to see some of my other projects.
> * Building and maintaining this **free** library takes a lot of my time and **saves you time**. Please consider paying it forward by supporting me with a small amount to my [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=contact%40jonkent%2eme&lc=US&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted). (only **13** people have donated since 12/23/15 but **thank you** to those who have!)
* **[Overview](#overview)**
* [Preview Samples](#preview-samples)
* **[Requirements](#requirements)**
* **[Installation](#installation)**
* [CocoaPods](#cocoapods)
* [Carthage](#carthage)
* [Swift Package Manager](#swift-package-manager)
* **[Usage](#usage)**
* [Code-less Storyboard Implementation](#code-less-storyboard-implementation)
* [Code Implementation](#code-implementation)
* **[Customization](#customization)**
* [SideMenuManager](#sidemenumanager)
* [SideMenuNavigationController](#sidemenunavigationcontroller)
* [SideMenuNavigationControllerDelegate](#sidemenunavigationcontrollerdelegate)
* [Advanced](#advanced)
* [Known Issues](#known-issues)
* [Thank You](#thank-you)
* [License](#license)
## Overview
SideMenu is a simple and versatile side menu control written in Swift.
* **It can be implemented in storyboard without a single line of [code](#code-less-storyboard-implementation).**
* Four standard animation styles to choose from (there's even a parallax effect if you want to get weird).
* Highly customizable without needing to write tons of custom code.
* Supports continuous swiping between side menus on boths sides in a single gesture.
* Global menu configuration. Set-up once and be done for all screens.
* Menus can be presented and dismissed the same as any other view controller since this control uses [custom transitions](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/CustomizingtheTransitionAnimations.html).
* Animations use your view controllers, not snapshots.
- [x] **It can be implemented in storyboard without a single line of [code](#code-less-storyboard-implementation).**
- [x] Eight standard animation styles to choose from (there's even a parallax effect if you want to get weird).
- [x] Highly customizable without needing to write tons of custom code.
- [x] Supports continuous swiping between side menus on boths sides in a single gesture.
- [x] Global menu configuration. Set-up once and be done for all screens.
- [x] Menus can be presented and dismissed the same as any other view controller since this control uses [custom transitions](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/CustomizingtheTransitionAnimations.html).
- [x] Animations use your view controllers, not snapshots.
- [x] Properly handles screen rotation and in-call status bar height changes.
Check out the example project to see it in action!
### Preview Samples
| Slide Out | Slide In | Dissolve | Slide In + Out |
| --- | --- | --- | --- |
| ![](etc/SlideOut.gif) | ![](etc/SlideIn.gif) | ![](etc/Dissolve.gif) | ![](etc/InOut.gif) |
| ![](https://raw.githubusercontent.com/jonkykong/SideMenu/master/etc/SlideOut.gif) | ![](https://raw.githubusercontent.com/jonkykong/SideMenu/master/etc/SlideIn.gif) | ![](https://raw.githubusercontent.com/jonkykong/SideMenu/master/etc/Dissolve.gif) | ![](https://raw.githubusercontent.com/jonkykong/SideMenu/master/etc/InOut.gif) |
## Requirements
* iOS 8 or higher
- [x] Xcode 11.
- [x] Swift 5.
- [x] iOS 10 or higher.
## Installation
### CocoaPods
@@ -42,13 +68,16 @@ To integrate SideMenu into your Xcode project using CocoaPods, specify it in you
```ruby
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
platform :ios, '10.0'
use_frameworks!
pod 'SideMenu'
# For Swift 2.3 (no longer maintained), use:
# pod 'SideMenu', '~> 1.2.1'
# For Swift 5 use:
# pod 'SideMenu', '~> 6.0'
# For Swift 4.2 (no longer maintained) use:
# pod 'SideMenu', '~> 5.0'
```
Then, run the following command:
@@ -74,16 +103,28 @@ To integrate SideMenu into your Xcode project using Carthage, specify it in your
github "jonkykong/SideMenu" "master"
```
### Swift Package Manager
The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. It is in early development, but SideMenu does support its use on supported platforms.
Once you have your Swift package set up, adding SideMenu as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.
```swift
dependencies: [
.package(url: "https://github.com/jonkykong/SideMenu.git", from: "6.0.0")
]
```
## Usage
### Code-less Storyboard Implementation
1. Create a Navigation Controller for a side menu. Set the `Custom Class` of the Navigation Controller to be `UISideMenuNavigationController` in the **Identity Inspector**. Set the `Module` to `SideMenu` (ignore this step if you've manually added SideMenu to your project). Create a Root View Controller for the Navigation Controller (shown as a UITableViewController below). Set up any Triggered Segues you want in that view controller.
![](etc/Screenshot1.png)
1. Create a Navigation Controller for a side menu. Set the `Custom Class` of the Navigation Controller to be `SideMenuNavigationController` in the **Identity Inspector**. Set the `Module` to `SideMenu` (ignore this step if you've manually added SideMenu to your project). Create a Root View Controller for the Navigation Controller (shown as a UITableViewController below). Set up any Triggered Segues you want in that view controller.
![](https://raw.githubusercontent.com/jonkykong/SideMenu/master/etc/Screenshot1.png)
2. Set the `Left Side` property of the `UISideMenuNavigationController` to On if you want it to appear from the left side of the screen, or Off/Default if you want it to appear from the right side.
![](etc/Screenshot2.png)
2. Set the `Left Side` property of the `SideMenuNavigationController` to On if you want it to appear from the left side of the screen, or Off/Default if you want it to appear from the right side.
![](https://raw.githubusercontent.com/jonkykong/SideMenu/master/etc/Screenshot2.png)
3. Add a UIButton or UIBarButton to a view controller that you want to display the menu from. Set that button's Triggered Segues action to modally present the Navigation Controller from step 1.
![](etc/Screenshot3.png)
![](https://raw.githubusercontent.com/jonkykong/SideMenu/master/etc/Screenshot3.png)
That's it. *Note: you can only enable gestures in code.*
### Code Implementation
@@ -92,145 +133,66 @@ First:
import SideMenu
```
In your view controller's `viewDidLoad` event, do something like this (**IMPORTANT: If you're seeing a black menu when you use gestures, read this section carefully!**):
From a button, do something like this:
``` swift
// Define the menu
let menu = SideMenuNavigationController(rootViewController: YourViewController)
// SideMenuNavigationController is a subclass of UINavigationController, so do any additional configuration
// of it here like setting its viewControllers. If you're using storyboards, you'll want to do something like:
// let menu = storyboard!.instantiateViewController(withIdentifier: "RightMenu") as! SideMenuNavigationController
present(menu, animated: true, completion: nil)
```
To dismiss a menu programmatically, do something like this:
``` swift
dismiss(animated: true, completion: nil)
```
To use gestures you have to use the `SideMenuManager`. In your `AppDelegate` do something like this:
``` swift
// Define the menus
let menuLeftNavigationController = UISideMenuNavigationController(rootViewController: YourViewController)
menuLeftNavigationController.leftSide = true
// UISideMenuNavigationController is a subclass of UINavigationController, so do any additional configuration
// of it here like setting its viewControllers. If you're using storyboards, you'll want to do something like:
// let menuLeftNavigationController = storyboard!.instantiateViewController(withIdentifier: "LeftMenuNavigationController") as! UISideMenuNavigationController
SideMenuManager.menuLeftNavigationController = menuLeftNavigationController
let leftMenuNavigationController = SideMenuNavigationController(rootViewController: YourViewController)
SideMenuManager.default.leftMenuNavigationController = leftMenuNavigationController
let menuRightNavigationController = UISideMenuNavigationController(rootViewController: YourViewController)
// UISideMenuNavigationController is a subclass of UINavigationController, so do any additional configuration
// of it here like setting its viewControllers. If you're using storyboards, you'll want to do something like:
// let menuRightNavigationController = storyboard!.instantiateViewController(withIdentifier: "RightMenuNavigationController") as! UISideMenuNavigationController
SideMenuManager.menuRightNavigationController = menuRightNavigationController
let rightMenuNavigationController = SideMenuNavigationController(rootViewController: YourViewController)
SideMenuManager.default.rightMenuNavigationController = rightMenuNavigationController
// Enable gestures. The left and/or right menus must be set up above for these to work.
// Setup gestures: the left and/or right menus must be set up (above) for these to work.
// Note that these continue to work on the Navigation Controller independent of the view controller it displays!
SideMenuManager.menuAddPanGestureToPresent(toView: self.navigationController!.navigationBar)
SideMenuManager.menuAddScreenEdgePanGesturesToPresent(toView: self.navigationController!.view)
```
Then from a button, do something like this:
``` swift
present(SideMenuManager.menuLeftNavigationController!, animated: true, completion: nil)
SideMenuManager.default.addPanGestureToPresent(toView: self.navigationController!.navigationBar)
SideMenuManager.default.addScreenEdgePanGesturesToPresent(toView: self.navigationController!.view)
// Similarly, to dismiss a menu programmatically, you would do this:
dismiss(animated: true, completion: nil)
// For Swift 2.3 (no longer maintained), use:
// presentViewController(SideMenuManager.menuLeftNavigationController!, animated: true, completion: nil)
// (Optional) Prevent status bar area from turning black when menu appears:
leftMenuNavigationController.statusBarEndAlpha = 0
// Copy all settings to the other menu
rightMenuNavigationController.settings = leftMenuNavigationController.settings
```
That's it.
### Customization
Just type `SideMenuManager.menu...` and code completion will show you everything you can customize (defaults are shown below for reference):
#### SideMenuManager
`SideMenuManager` supports the following:
``` swift
/**
The push style of the menu.
There are six modes in MenuPushStyle:
- defaultBehavior: The view controller is pushed onto the stack.
- popWhenPossible: If a view controller already in the stack is of the same class as the pushed view controller, the stack is instead popped back to the existing view controller. This behavior can help users from getting lost in a deep navigation stack.
- preserve: If a view controller already in the stack is of the same class as the pushed view controller, the existing view controller is pushed to the end of the stack. This behavior is similar to a UITabBarController.
- preserveAndHideBackButton: Same as .preserve and back buttons are automatically hidden.
- replace: Any existing view controllers are released from the stack and replaced with the pushed view controller. Back buttons are automatically hidden. This behavior is ideal if view controllers require a lot of memory or their state doesn't need to be preserved..
- subMenu: Unlike all other behaviors that push using the menu's presentingViewController, this behavior pushes view controllers within the menu. Use this behavior if you want to display a sub menu.
*/
open static var menuPushStyle: MenuPushStyle = .defaultBehavior
/**
The presentation mode of the menu.
There are four modes in MenuPresentMode:
- menuSlideIn: Menu slides in over of the existing view.
- viewSlideOut: The existing view slides out to reveal the menu.
- viewSlideInOut: The existing view slides out while the menu slides in.
- menuDissolveIn: The menu dissolves in over the existing view controller.
*/
open static var menuPresentMode: MenuPresentMode = .viewSlideOut
/// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true.
open static var menuAllowPushOfSameClassTwice = true
/// Width of the menu when presented on screen, showing the existing view controller in the remaining space. Default is 75% of the screen width.
open static var menuWidth: CGFloat = max(round(min((appScreenRect.width), (appScreenRect.height)) * 0.75), 240)
/// Duration of the animation when the menu is presented without gestures. Default is 0.35 seconds.
open static var menuAnimationPresentDuration = 0.35
/// Duration of the animation when the menu is dismissed without gestures. Default is 0.35 seconds.
open static var menuAnimationDismissDuration = 0.35
/// Amount to fade the existing view controller when the menu is presented. Default is 0 for no fade. Set to 1 to fade completely.
open static var menuAnimationFadeStrength: CGFloat = 0
/// The amount to scale the existing view controller or the menu view controller depending on the `menuPresentMode`. Default is 1 for no scaling. Less than 1 will shrink, greater than 1 will grow.
open static var menuAnimationTransformScaleFactor: CGFloat = 1
/// The background color behind menu animations. Depending on the animation settings this may not be visible. If `menuFadeStatusBar` is true, this color is used to fade it. Default is black.
open static var menuAnimationBackgroundColor: UIColor?
/// The shadow opacity around the menu view controller or existing view controller depending on the `menuPresentMode`. Default is 0.5 for 50% opacity.
open static var menuShadowOpacity: Float = 0.5
/// The shadow color around the menu view controller or existing view controller depending on the `menuPresentMode`. Default is black.
open static var menuShadowColor = UIColor.black
/// The radius of the shadow around the menu view controller or existing view controller depending on the `menuPresentMode`. Default is 5.
open static var menuShadowRadius: CGFloat = 5
/// The left menu swipe to dismiss gesture.
open static weak var menuLeftSwipeToDismissGesture: UIPanGestureRecognizer?
/// The right menu swipe to dismiss gesture.
open static weak var menuRightSwipeToDismissGesture: UIPanGestureRecognizer?
/// Enable or disable gestures that would swipe to dismiss the menu. Default is true.
open static var menuEnableSwipeGestures: Bool = true
/// Enable or disable interaction with the presenting view controller while the menu is displayed. Enabling may make it difficult to dismiss the menu or cause exceptions if the user tries to present and already presented menu. Default is false.
open static var menuPresentingViewControllerUserInteractionEnabled: Bool = false
/// The strength of the parallax effect on the existing view controller. Does not apply to `menuPresentMode` when set to `ViewSlideOut`. Default is 0.
open static var menuParallaxStrength: Int = 0
/// Draws the `menuAnimationBackgroundColor` behind the status bar. Default is true.
open static var menuFadeStatusBar = true
/// The animation options when a menu is displayed. Ignored when displayed with a gesture.
open static var menuAnimationOptions: UIViewAnimationOptions = .curveEaseInOut
/// The animation spring damping when a menu is displayed. Ignored when displayed with a gesture.
open static var menuAnimationUsingSpringWithDamping: CGFloat = 1
/// The animation initial spring velocity when a menu is displayed. Ignored when displayed with a gesture.
open static var menuAnimationInitialSpringVelocity: CGFloat = 1
/**
The blur effect style of the menu if the menu's root view controller is a UITableViewController or UICollectionViewController.
- Note: If you want cells in a UITableViewController menu to show vibrancy, make them a subclass of UITableViewVibrantCell.
*/
open static var menuBlurEffectStyle: UIBlurEffectStyle?
/// The left menu.
open static var menuLeftNavigationController: UISideMenuNavigationController?
open var leftMenuNavigationController: SideMenuNavigationController?
/// The right menu.
open static var menuRightNavigationController: UISideMenuNavigationController?
public var rightMenuNavigationController: SideMenuNavigationController?
/**
Adds screen edge gestures for both left and right sides to a view to present a menu.
- Parameter toView: The view to add gestures to.
- Returns: The array of screen edge gestures added to `toView`.
*/
@discardableResult public func addScreenEdgePanGesturesToPresent(toView view: UIView) -> [UIScreenEdgePanGestureRecognizer]
/**
Adds screen edge gestures to a view to present a menu.
- Parameter toView: The view to add gestures to.
- Parameter forMenu: The menu (left or right) you want to add a gesture for. If unspecified, gestur=es will be added for both sides.
- Parameter forMenu: The menu (left or right) you want to add a gesture for.
- Returns: The array of screen edge gestures added to `toView`.
- Returns: The screen edge gestures added to `toView`.
*/
@discardableResult open class func menuAddScreenEdgePanGesturesToPresent(toView: UIView, forMenu:UIRectEdge? = nil) -> [UIScreenEdgePanGestureRecognizer]
@discardableResult public func addScreenEdgePanGesturesToPresent(toView view: UIView, forMenu side: PresentDirection) -> UIScreenEdgePanGestureRecognizer
/**
Adds a pan edge gesture to a view to present menus.
@@ -238,11 +200,204 @@ open static var menuRightNavigationController: UISideMenuNavigationController?
- Returns: The pan gesture added to `toView`.
*/
@discardableResult open class func menuAddPanGestureToPresent(toView: UIView) -> UIPanGestureRecognizer
@discardableResult public func addPanGestureToPresent(toView view: UIView) -> UIPanGestureRecognizer
```
#### SideMenuNavigationController
`SideMenuNavigationController` supports the following:
``` swift
/// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true.
var allowPushOfSameClassTwice: Bool = true
/// Forces menus to always animate when appearing or disappearing, regardless of a pushed view controller's animation.
var alwaysAnimate: Bool = true
/// The animation options when a menu is displayed. Ignored when displayed with a gesture.
var animationOptions: UIView.AnimationOptions = .curveEaseInOut
/**
The blur effect style of the menu if the menu's root view controller is a UITableViewController or UICollectionViewController.
- Note: If you want cells in a UITableViewController menu to show vibrancy, make them a subclass of UITableViewVibrantCell.
*/
var blurEffectStyle: UIBlurEffect.Style? = nil
/// Duration of the remaining animation when the menu is partially dismissed with gestures. Default is 0.35 seconds.
var completeGestureDuration: Double = 0.35
/// Animation curve of the remaining animation when the menu is partially dismissed with gestures. Default is .easeIn.
var completionCurve: UIView.AnimationCurve = .curveEaseInOut
/// Duration of the animation when the menu is dismissed without gestures. Default is 0.35 seconds.
var dismissDuration: Double = 0.35
/// Automatically dismisses the menu when another view is presented from it.
var dismissOnPresent: Bool = true
/// Automatically dismisses the menu when another view controller is pushed from it.
var dismissOnPush: Bool = true
/// Automatically dismisses the menu when the screen is rotated.
var dismissOnRotation: Bool = true
/// Automatically dismisses the menu when app goes to the background.
var dismissWhenBackgrounded: Bool = true
/// Enable or disable a swipe gesture that dismisses the menu. Will not be triggered when `presentingViewControllerUserInteractionEnabled` is set to true. Default is true.
var enableSwipeToDismissGesture: Bool = true
/// Enable or disable a tap gesture that dismisses the menu. Will not be triggered when `presentingViewControllerUserInteractionEnabled` is set to true. Default is true.
var enableTapToDismissGesture: Bool = true
/// The animation initial spring velocity when a menu is displayed. Ignored when displayed with a gesture.
var initialSpringVelocity: CGFloat = 1
/// Whether the menu appears on the right or left side of the screen. Right is the default. This property cannot be changed after the menu has loaded.
var leftSide: Bool = false
/// Width of the menu when presented on screen, showing the existing view controller in the remaining space. Default is zero.
var menuWidth: CGFloat = 240
/// Duration of the animation when the menu is presented without gestures. Default is 0.35 seconds.
var presentDuration: Double = 0.35
/// Enable or disable interaction with the presenting view controller while the menu is displayed. Enabling may make it difficult to dismiss the menu or cause exceptions if the user tries to present and already presented menu. `presentingViewControllerUseSnapshot` must also set to false. Default is false.
var presentingViewControllerUserInteractionEnabled: Bool = false
/// Use a snapshot for the presenting vierw controller while the menu is displayed. Useful when layout changes occur during transitions. Not recommended for apps that support rotation. Default is false.
var presentingViewControllerUseSnapshot: Bool = false
/// The presentation style of the menu.
var presentationStyle: SideMenuPresentStyle = .viewSlideOut
/**
The push style of the menu.
There are six modes in MenuPushStyle:
- defaultBehavior: The view controller is pushed onto the stack.
- popWhenPossible: If a view controller already in the stack is of the same class as the pushed view controller, the stack is instead popped back to the existing view controller. This behavior can help users from getting lost in a deep navigation stack.
- preserve: If a view controller already in the stack is of the same class as the pushed view controller, the existing view controller is pushed to the end of the stack. This behavior is similar to a UITabBarController.
- preserveAndHideBackButton: Same as .preserve and back buttons are automatically hidden.
- replace: Any existing view controllers are released from the stack and replaced with the pushed view controller. Back buttons are automatically hidden. This behavior is ideal if view controllers require a lot of memory or their state doesn't need to be preserved..
- subMenu: Unlike all other behaviors that push using the menu's presentingViewController, this behavior pushes view controllers within the menu. Use this behavior if you want to display a sub menu.
*/
var pushStyle: MenuPushStyle = .default
/// Draws `presentationStyle.backgroundColor` behind the status bar. Default is 0.
var statusBarEndAlpha: CGFloat = 0
/// The animation spring damping when a menu is displayed. Ignored when displayed with a gesture.
var usingSpringWithDamping: CGFloat = 1
/// Indicates if the menu is anywhere in the view hierarchy, even if covered by another view controller.
var isHidden: Bool
```
#### SideMenuPresentStyle
There are 8 pre-defined `SideMenuPresentStyle` options:
``` swift
/// Menu slides in over the existing view.
static let menuSlideIn: SideMenuPresentStyle
/// The existing view slides out to reveal the menu underneath.
static let viewSlideOut: SideMenuPresentStyle
/// The existing view slides out while the menu slides in.
static let viewSlideOutMenuIn: SideMenuPresentStyle
/// The menu dissolves in over the existing view.
static let menuDissolveIn: SideMenuPresentStyle
/// The existing view slides out while the menu partially slides in.
static let viewSlideOutMenuPartialIn: SideMenuPresentStyle
/// The existing view slides out while the menu slides out from under it.
static let viewSlideOutMenuOut: SideMenuPresentStyle
/// The existing view slides out while the menu partially slides out from under it.
static let viewSlideOutMenuPartialOut: SideMenuPresentStyle
/// The existing view slides out and shrinks to reveal the menu underneath.
static let viewSlideOutMenuZoom: SideMenuPresentStyle
```
#### SideMenuNavigationControllerDelegate
To receive notifications when a menu is displayed from a view controller, have it adhere to the `SideMenuNavigationControllerDelegate` protocol:
``` swift
extension MyViewController: SideMenuNavigationControllerDelegate {
func sideMenuWillAppear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Appearing! (animated: \(animated))")
}
func sideMenuDidAppear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Appeared! (animated: \(animated))")
}
func sideMenuWillDisappear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Disappearing! (animated: \(animated))")
}
func sideMenuDidDisappear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Disappeared! (animated: \(animated))")
}
}
```
*Note: setting the `sideMenuDelegate` property on `SideMenuNavigationController` is optional. If your view controller adheres to the protocol then the methods will be called automatically.*
### Advanced
<details>
<summary>Click for Details</summary>
#### Multiple SideMenuManagers
For simplicity, `SideMenuManager.default` serves as the primary instance as most projects will only need one menu across all screens. If you need to show a different SideMenu using gestures, such as from a modal view controller presented from a previous SideMenu, do the following:
1. Declare a variable containing your custom `SideMenuManager` instance. You may want it to define it globally and configure it in your app delegate if menus will be used on multiple screens.
``` swift
let customSideMenuManager = SideMenuManager()
```
2. Setup and display menus with your custom instance the same as you would with the `SideMenuManager.default` instance.
3. If using Storyboards, subclass your instance of `SideMenuNavigationController` and set its `sideMenuManager` property to your custom instance. This must be done before `viewDidLoad` is called:
``` swift
class MySideMenuNavigationController: SideMenuNavigationController {
let customSideMenuManager = SideMenuManager()
override func awakeFromNib() {
super.awakeFromNib()
sideMenuManager = customSideMenuManager
}
}
```
Alternatively, you can set `sideMenuManager` from the view controller that segues to your SideMenuNavigationController:
``` swift
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let sideMenuNavigationController = segue.destination as? SideMenuNavigationController {
sideMenuNavigationController.sideMenuManager = customSideMenuManager
}
}
```
*Important: displaying SideMenu instances directly over each other is not supported. Use `menuPushStyle = .subMenu` to display multi-level menus instead.*
### SideMenuPresentationStyle
If you want to create your own custom presentation style, create a subclass of `SideMenuPresentationStyle` and set your menu's `presentationStyle` to it:
```swift
class MyPresentStyle: SideMenuPresentationStyle {
override init() {
super.init()
/// Background color behind the views and status bar color
backgroundColor = .black
/// The starting alpha value of the menu before it appears
menuStartAlpha = 1
/// Whether or not the menu is on top. If false, the presenting view is on top. Shadows are applied to the view on top.
menuOnTop = false
/// The amount the menu is translated along the x-axis. Zero is stationary, negative values are off-screen, positive values are on screen.
menuTranslateFactor = 0
/// The amount the menu is scaled. Less than one shrinks the view, larger than one grows the view.
menuScaleFactor = 1
/// The color of the shadow applied to the top most view.
onTopShadowColor = .black
/// The radius of the shadow applied to the top most view.
onTopShadowRadius = 5
/// The opacity of the shadow applied to the top most view.
onTopShadowOpacity = 0
/// The offset of the shadow applied to the top most view.
onTopShadowOffset = .zero
/// The ending alpha of the presenting view when the menu is fully displayed.
presentingEndAlpha = 1
/// The amount the presenting view is translated along the x-axis. Zero is stationary, negative values are off-screen, positive values are on screen.
presentingTranslateFactor = 0
/// The amount the presenting view is scaled. Less than one shrinks the view, larger than one grows the view.
presentingScaleFactor = 1
/// The strength of the parallax effect on the presenting view once the menu is displayed.
presentingParallaxStrength = .zero
}
/// This method is called just before the presentation transition begins. Use this to setup any animations. The super method does not need to be called.
override func presentationTransitionWillBegin(to presentedViewController: UIViewController, from presentingViewController: UIViewController) {}
/// This method is called during the presentation animation. Use this to animate anything alongside the menu animation. The super method does not need to be called.
override func presentationTransition(to presentedViewController: UIViewController, from presentingViewController: UIViewController) {}
/// This method is called when the presentation transition ends. Use this to finish any animations. The super method does not need to be called.
override func presentationTransitionDidEnd(to presentedViewController: UIViewController, from presentingViewController: UIViewController, _ completed: Bool) {}
/// This method is called just before the dismissal transition begins. Use this to setup any animations. The super method does not need to be called.
override func dismissalTransitionWillBegin(to presentedViewController: UIViewController, from presentingViewController: UIViewController) {}
/// This method is called during the dismissal animation. Use this to animate anything alongside the menu animation. The super method does not need to be called.
override func dismissalTransition(to presentedViewController: UIViewController, from presentingViewController: UIViewController) {}
/// This method is called when the dismissal transition ends. Use this to finish any animations. The super method does not need to be called.
override func dismissalTransitionDidEnd(to presentedViewController: UIViewController, from presentingViewController: UIViewController, _ completed: Bool) {}
}
```
</details>
## Known Issues
Don't try to change the status bar appearance when presenting a menu. When used with quick gestures/animations, it causes the presentation animation to not complete properly and locks the UI. This was fixed in iOS 9.3. See [radar 21961293](http://www.openradar.me/21961293) for more information.
* Issue [#258](https://github.com/jonkykong/SideMenu/issues/258). Using `presentingViewControllerUseSnapshot` can help preserve the experience.
## Thank You
A special thank you to everyone that has [contributed](https://github.com/jonkykong/SideMenu/graphs/contributors) to this library to make it better. Your support is appreciated!
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
@@ -0,0 +1,34 @@
//
// SideMenu__SwiftUI_Tests.swift
// SideMenu (SwiftUI)Tests
//
// Created by Jon Kent on 10/19/20.
// Copyright © 2020 jonkykong. All rights reserved.
//
import XCTest
@testable import SideMenu__SwiftUI_
class SideMenu__SwiftUI_Tests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() throws {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
@@ -0,0 +1,43 @@
//
// SideMenu__SwiftUI_UITests.swift
// SideMenu (SwiftUI)UITests
//
// Created by Jon Kent on 10/19/20.
// Copyright © 2020 jonkykong. All rights reserved.
//
import XCTest
class SideMenu__SwiftUI_UITests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
continueAfterFailure = false
// In UI tests its important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() throws {
// UI tests must launch the application that they test.
let app = XCUIApplication()
app.launch()
// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testLaunchPerformance() throws {
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
// This measures how long it takes to launch your application.
measure(metrics: [XCTApplicationLaunchMetric()]) {
XCUIApplication().launch()
}
}
}
}
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
+22
View File
@@ -0,0 +1,22 @@
//
// ContentView.swift
// SideMenu (SwiftUI)
//
// Created by Jon Kent on 10/19/20.
// Copyright © 2020 jonkykong. All rights reserved.
//
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
+57
View File
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>SideMenu</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
</dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchScreen</key>
<dict/>
<key>UILaunchStoryboardName</key>
<string>Launch Screen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,18 @@
//
// SideMenu__SwiftUI_App.swift
// SideMenu (SwiftUI)
//
// Created by Jon Kent on 10/19/20.
// Copyright © 2020 jonkykong. All rights reserved.
//
import SwiftUI
@main
struct SideMenu__SwiftUI_App: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
@@ -0,0 +1,78 @@
//
// ExampleTests.swift
// ExampleTests
//
// Created by Jon Kent on 8/10/19.
// Copyright © 2019 jonkykong. All rights reserved.
//
import XCTest
class ExampleTests: XCTestCase {
private let styleTitles = ["Slide In", "Slide Out", "In + Out", "Dissolve"]
private let swipeHere = "Swipe Here"
private let app = XCUIApplication()
private var mainViewController: XCUIElement {
return app.navigationBars[swipeHere]
}
override func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
continueAfterFailure = false
// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
XCUIApplication().launch()
// In UI tests its important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testTapLeft() {
let elementsQuery = app.scrollViews.otherElements
for title in styleTitles {
elementsQuery.buttons[title].tap()
mainViewController.buttons["Left Menu"].tap()
app.tables/*@START_MENU_TOKEN@*/.staticTexts["Push View Controller 1"]/*[[".cells.staticTexts[\"Push View Controller 1\"]",".staticTexts[\"Push View Controller 1\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.tap()
app.navigationBars["You Can Still Swipe!"].buttons[swipeHere].tap()
validate()
}
}
func testTapRight() {
let elementsQuery = app.scrollViews.otherElements
for title in styleTitles {
elementsQuery.buttons[title].tap()
mainViewController.buttons["Right Menu"].tap()
app.tables/*@START_MENU_TOKEN@*/.staticTexts["Present View Controller 1"]/*[[".cells.staticTexts[\"Present View Controller 1\"]",".staticTexts[\"Present View Controller 1\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.tap()
app.buttons["Dismiss"].tap()
mainViewController.tap()
validate()
}
}
func testSwiping() {
mainViewController.swipeRight()
mainViewController.swipeLeft()
validate()
mainViewController.swipeLeft()
mainViewController.swipeRight()
validate()
}
private func validate() {
XCTAssertTrue(mainViewController.exists)
}
/* TODO - More tests:
- Rotation
- All menu settings
*/
}
@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@@ -16,8 +16,6 @@
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
@@ -13,8 +13,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
fileprivate func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [AnyHashable: Any]?) -> Bool {
private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [AnyHashable: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
@@ -40,7 +39,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
@@ -1,5 +1,15 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
@@ -29,6 +39,11 @@
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {

Before

Width:  |  Height:  |  Size: 921 KiB

After

Width:  |  Height:  |  Size: 921 KiB

Before

Width:  |  Height:  |  Size: 573 KiB

After

Width:  |  Height:  |  Size: 573 KiB

+51
View File
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="8es-i5-QRh">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Navigation Controller-->
<scene sceneID="VDo-YK-ZHx">
<objects>
<navigationController id="8es-i5-QRh" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" id="XHs-h3-Wt0">
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<gestureRecognizers/>
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</navigationBar>
<connections>
<segue destination="gQC-s5-YYp" kind="relationship" relationship="rootViewController" id="hL1-vz-erR"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Xx8-5L-ee5" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-561" y="336.99999999999994"/>
</scene>
<!--View Controller-->
<scene sceneID="Ksu-iT-xHl">
<objects>
<viewController id="gQC-s5-YYp" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="ZZW-BN-qTx">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="Z5N-rE-oLS"/>
</view>
<navigationItem key="navigationItem" id="NJs-Nl-tMd">
<barButtonItem key="backBarButtonItem" title=" " id="Z6X-gi-A0H"/>
</navigationItem>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="rlc-KC-ZA1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="142" y="336"/>
</scene>
</scenes>
</document>
@@ -1,12 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2555" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="yAA-s6-Bam">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="yAA-s6-Bam">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@@ -15,7 +13,7 @@
<objects>
<navigationController id="yAA-s6-Bam" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" id="Bue-4e-bCJ">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<gestureRecognizers/>
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -33,111 +31,24 @@
<scene sceneID="XZh-dw-B7D">
<objects>
<viewController id="QHN-nZ-kbB" customClass="MainViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Rm7-bv-OCN"/>
<viewControllerLayoutGuide type="bottom" id="LW0-9z-RHu"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="0gg-po-Ih1">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LFJ-SB-Zp9">
<rect key="frame" x="0.0" y="0.0" width="375" height="635"/>
<rect key="frame" x="0.0" y="44" width="375" height="591"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="DMn-tw-NTB">
<rect key="frame" x="0.0" y="0.0" width="375" height="469"/>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="iBe-qv-i0y">
<rect key="frame" x="20" y="20" width="335" height="681"/>
<subviews>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="pqT-4M-nw1">
<rect key="frame" x="18" y="167" width="339" height="31"/>
<color key="thumbTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeSlider:" destination="QHN-nZ-kbB" eventType="valueChanged" id="Kcj-yD-lS0"/>
</connections>
</slider>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Present Mode" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Efp-5L-qft">
<rect key="frame" x="20" y="8" width="154" height="20.5"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Presentation Style" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Efp-5L-qft">
<rect key="frame" x="0.0" y="0.0" width="335" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Screen Width" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Snj-Mg-6ww">
<rect key="frame" x="20" y="272" width="151" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<slider opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="Osf-2d-Znm">
<rect key="frame" x="18" y="234" width="339" height="31"/>
<color key="thumbTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeSlider:" destination="QHN-nZ-kbB" eventType="valueChanged" id="cRR-z8-cmm"/>
</connections>
</slider>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" translatesAutoresizingMaskIntoConstraints="NO" id="owH-AA-wgw">
<rect key="frame" x="20" y="102" width="335" height="29"/>
<segments>
<segment title="None"/>
<segment title="Dark"/>
<segment title="Light"/>
<segment title="ExtraLight"/>
</segments>
<connections>
<action selector="changeSegment:" destination="QHN-nZ-kbB" eventType="valueChanged" id="Mna-Yh-fHu"/>
</connections>
</segmentedControl>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.001" minValue="0.001" maxValue="2" translatesAutoresizingMaskIntoConstraints="NO" id="Xp9-C5-Td1">
<rect key="frame" x="18" y="368" width="339" height="31"/>
<color key="thumbTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeSlider:" destination="QHN-nZ-kbB" eventType="valueChanged" id="PMM-8h-apN"/>
</connections>
</slider>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Shadow Opacity" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2QC-6F-Xpx">
<rect key="frame" x="20" y="205" width="172.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="Cor-r1-osR">
<rect key="frame" x="18" y="301" width="339" height="31"/>
<color key="thumbTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeSlider:" destination="QHN-nZ-kbB" eventType="valueChanged" id="TSE-rt-Run"/>
</connections>
</slider>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Transform Scale Factor" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Tsg-30-YHs">
<rect key="frame" x="20" y="339" width="225" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Blur Style" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OHe-SA-S0e">
<rect key="frame" x="20" y="73" width="120.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Fade Strength" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tRs-iN-9Ht">
<rect key="frame" x="20" y="138" width="155.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Fade Status Bar" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Gtc-KE-FIO">
<rect key="frame" x="20" y="423.5" width="168.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oFS-2Q-kPB">
<rect key="frame" x="306" y="418" width="51" height="31"/>
<color key="onTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeSwitch:" destination="QHN-nZ-kbB" eventType="valueChanged" id="2wD-Py-Q4n"/>
</connections>
</switch>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" translatesAutoresizingMaskIntoConstraints="NO" id="KV2-tN-Aff">
<rect key="frame" x="20" y="37" width="335" height="29"/>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="KV2-tN-Aff">
<rect key="frame" x="0.0" y="28.5" width="335" height="32"/>
<segments>
<segment title="Slide In"/>
<segment title="Slide Out"/>
@@ -145,59 +56,185 @@
<segment title="Dissolve"/>
</segments>
<connections>
<action selector="changeSegment:" destination="QHN-nZ-kbB" eventType="valueChanged" id="B2a-9p-5O1"/>
<action selector="changeControl:" destination="QHN-nZ-kbB" eventType="valueChanged" id="y76-7g-AuZ"/>
</connections>
</segmentedControl>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wsl-iY-a5K">
<rect key="frame" x="0.0" y="67.5" width="335" height="4"/>
<constraints>
<constraint firstAttribute="height" constant="4" id="oRw-Gi-ezT"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Blur Style" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OHe-SA-S0e">
<rect key="frame" x="0.0" y="79.5" width="335" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" translatesAutoresizingMaskIntoConstraints="NO" id="owH-AA-wgw">
<rect key="frame" x="0.0" y="108" width="335" height="32"/>
<segments>
<segment title="None"/>
<segment title="Dark"/>
<segment title="Light"/>
<segment title="ExtraLight"/>
</segments>
<connections>
<action selector="changeControl:" destination="QHN-nZ-kbB" eventType="valueChanged" id="UkJ-YS-OXg"/>
</connections>
</segmentedControl>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="svy-p5-tiL">
<rect key="frame" x="0.0" y="147" width="335" height="4"/>
<constraints>
<constraint firstAttribute="height" constant="4" id="wra-S3-qWU"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Start Alpha" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tRs-iN-9Ht">
<rect key="frame" x="0.0" y="159" width="335" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="pqT-4M-nw1">
<rect key="frame" x="-2" y="187.5" width="339" height="31"/>
<color key="thumbTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeControl:" destination="QHN-nZ-kbB" eventType="valueChanged" id="Rfw-ZT-ziI"/>
</connections>
</slider>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="r3M-VQ-eCj">
<rect key="frame" x="0.0" y="225.5" width="335" height="4"/>
<constraints>
<constraint firstAttribute="height" constant="4" id="RvV-Fo-ext"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Presenting End Alpha" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NmN-uG-ABp">
<rect key="frame" x="0.0" y="237.5" width="335" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="xlA-NK-mN4">
<rect key="frame" x="-2" y="266" width="339" height="31"/>
<color key="thumbTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeControl:" destination="QHN-nZ-kbB" eventType="valueChanged" id="ah6-OO-Zh9"/>
</connections>
</slider>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bjn-LU-15M">
<rect key="frame" x="0.0" y="304" width="335" height="4"/>
<constraints>
<constraint firstAttribute="height" constant="4" id="jLL-oP-eBj"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Shadow Opacity" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2QC-6F-Xpx">
<rect key="frame" x="0.0" y="316" width="335" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<slider opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="Osf-2d-Znm">
<rect key="frame" x="-2" y="344.5" width="339" height="31"/>
<color key="thumbTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeControl:" destination="QHN-nZ-kbB" eventType="valueChanged" id="Vw7-lT-kal"/>
</connections>
</slider>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cKX-Y9-C8e">
<rect key="frame" x="0.0" y="382.5" width="335" height="4"/>
<constraints>
<constraint firstAttribute="height" constant="4" id="6m5-zX-BY6"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Screen Width" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Snj-Mg-6ww">
<rect key="frame" x="0.0" y="394.5" width="335" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="Cor-r1-osR">
<rect key="frame" x="-2" y="423" width="339" height="31"/>
<color key="thumbTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeControl:" destination="QHN-nZ-kbB" eventType="valueChanged" id="QfP-ZL-gGs"/>
</connections>
</slider>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="03z-3b-0TF">
<rect key="frame" x="0.0" y="461" width="335" height="4"/>
<constraints>
<constraint firstAttribute="height" constant="4" id="Kf2-9J-fIV"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Scale Factor" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Tsg-30-YHs">
<rect key="frame" x="0.0" y="473" width="335" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.001" minValue="0.001" maxValue="2" translatesAutoresizingMaskIntoConstraints="NO" id="Xp9-C5-Td1">
<rect key="frame" x="-2" y="501.5" width="339" height="31"/>
<color key="thumbTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeControl:" destination="QHN-nZ-kbB" eventType="valueChanged" id="lNd-9Z-lpP"/>
</connections>
</slider>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FrH-kR-j43">
<rect key="frame" x="0.0" y="539.5" width="335" height="4"/>
<constraints>
<constraint firstAttribute="height" constant="4" id="9kG-hd-eZS"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Presenting Scale Factor" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="j7p-7c-wlI">
<rect key="frame" x="0.0" y="551.5" width="335" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.001" minValue="0.001" maxValue="2" translatesAutoresizingMaskIntoConstraints="NO" id="Oso-tQ-0MO">
<rect key="frame" x="-2" y="580" width="339" height="31"/>
<color key="thumbTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeControl:" destination="QHN-nZ-kbB" eventType="valueChanged" id="TuI-Au-hWY"/>
</connections>
</slider>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="DMn-tw-NTB">
<rect key="frame" x="0.0" y="618" width="335" height="63"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Menu Fade Status Bar" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Gtc-KE-FIO">
<rect key="frame" x="0.0" y="17.5" width="168.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oFS-2Q-kPB">
<rect key="frame" x="286" y="12" width="51" height="31"/>
<color key="onTintColor" red="0.25098040700000002" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeControl:" destination="QHN-nZ-kbB" eventType="valueChanged" id="07O-77-z6m"/>
</connections>
</switch>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="oFS-2Q-kPB" secondAttribute="bottom" constant="20" id="JOj-wa-d77"/>
<constraint firstItem="Gtc-KE-FIO" firstAttribute="centerY" secondItem="oFS-2Q-kPB" secondAttribute="centerY" id="K3W-KT-drz"/>
<constraint firstAttribute="trailing" secondItem="oFS-2Q-kPB" secondAttribute="trailing" id="Srm-9Q-3KT"/>
<constraint firstItem="oFS-2Q-kPB" firstAttribute="top" secondItem="DMn-tw-NTB" secondAttribute="top" constant="12" id="rXQ-lL-9SH"/>
<constraint firstItem="Gtc-KE-FIO" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" id="rdp-LR-6EL"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="KV2-tN-Aff" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="0Xw-7D-HJS"/>
<constraint firstItem="pqT-4M-nw1" firstAttribute="top" secondItem="tRs-iN-9Ht" secondAttribute="bottom" constant="8.5" id="4E7-dh-BVN"/>
<constraint firstItem="Snj-Mg-6ww" firstAttribute="top" secondItem="Osf-2d-Znm" secondAttribute="bottom" constant="8" id="8Ao-Li-Epv"/>
<constraint firstAttribute="trailing" secondItem="KV2-tN-Aff" secondAttribute="trailing" constant="20" id="8Kt-Kr-IfW"/>
<constraint firstItem="Efp-5L-qft" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="9Ni-I7-vh7"/>
<constraint firstItem="tRs-iN-9Ht" firstAttribute="top" secondItem="owH-AA-wgw" secondAttribute="bottom" constant="8" id="9dH-pj-fjK"/>
<constraint firstItem="2QC-6F-Xpx" firstAttribute="top" secondItem="pqT-4M-nw1" secondAttribute="bottom" constant="8" id="Dop-eI-Rbx"/>
<constraint firstItem="owH-AA-wgw" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="Ges-hw-pKE"/>
<constraint firstItem="Tsg-30-YHs" firstAttribute="top" secondItem="Cor-r1-osR" secondAttribute="bottom" constant="8" id="HRj-lJ-fP0"/>
<constraint firstItem="Cor-r1-osR" firstAttribute="top" secondItem="Snj-Mg-6ww" secondAttribute="bottom" constant="8.5" id="IiO-0v-8ZM"/>
<constraint firstAttribute="bottom" secondItem="oFS-2Q-kPB" secondAttribute="bottom" constant="20" id="JOj-wa-d77"/>
<constraint firstItem="Gtc-KE-FIO" firstAttribute="centerY" secondItem="oFS-2Q-kPB" secondAttribute="centerY" id="K3W-KT-drz"/>
<constraint firstItem="Tsg-30-YHs" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="LKY-Cl-eby"/>
<constraint firstItem="pqT-4M-nw1" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="NU7-Qv-W7e"/>
<constraint firstItem="tRs-iN-9Ht" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="NkW-aK-ri6"/>
<constraint firstAttribute="trailing" secondItem="Cor-r1-osR" secondAttribute="trailing" constant="20" id="Olk-Cf-bYo"/>
<constraint firstItem="OHe-SA-S0e" firstAttribute="top" secondItem="KV2-tN-Aff" secondAttribute="bottom" constant="8" id="PK0-Y3-fVe"/>
<constraint firstAttribute="trailing" secondItem="owH-AA-wgw" secondAttribute="trailing" constant="20" id="S3u-3a-WE4"/>
<constraint firstItem="Xp9-C5-Td1" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="SYl-4Z-bdP"/>
<constraint firstAttribute="trailing" secondItem="oFS-2Q-kPB" secondAttribute="trailing" constant="20" id="Srm-9Q-3KT"/>
<constraint firstItem="Osf-2d-Znm" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="TLj-8B-NIM"/>
<constraint firstAttribute="trailing" secondItem="Xp9-C5-Td1" secondAttribute="trailing" constant="20" id="ch1-dJ-pie"/>
<constraint firstItem="oFS-2Q-kPB" firstAttribute="top" secondItem="Xp9-C5-Td1" secondAttribute="bottom" constant="20" id="emb-zX-GbP"/>
<constraint firstItem="Cor-r1-osR" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="jPg-kK-NEg"/>
<constraint firstAttribute="trailing" secondItem="pqT-4M-nw1" secondAttribute="trailing" constant="20" id="jaX-aN-HJU"/>
<constraint firstItem="owH-AA-wgw" firstAttribute="top" secondItem="OHe-SA-S0e" secondAttribute="bottom" constant="8.5" id="lAg-sf-9xb"/>
<constraint firstAttribute="trailing" secondItem="Osf-2d-Znm" secondAttribute="trailing" constant="20" id="lS6-KH-Diz"/>
<constraint firstItem="Snj-Mg-6ww" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="mMS-Cb-uWu"/>
<constraint firstItem="KV2-tN-Aff" firstAttribute="top" secondItem="Efp-5L-qft" secondAttribute="bottom" constant="8.5" id="nqY-9A-okx"/>
<constraint firstItem="2QC-6F-Xpx" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="nwA-9O-eAJ"/>
<constraint firstItem="Gtc-KE-FIO" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="rdp-LR-6EL"/>
<constraint firstItem="OHe-SA-S0e" firstAttribute="leading" secondItem="DMn-tw-NTB" secondAttribute="leading" constant="20" id="sbb-k6-xRo"/>
<constraint firstItem="Efp-5L-qft" firstAttribute="top" secondItem="DMn-tw-NTB" secondAttribute="top" constant="8" id="tLT-mz-TL7"/>
<constraint firstItem="Xp9-C5-Td1" firstAttribute="top" secondItem="Tsg-30-YHs" secondAttribute="bottom" constant="8.5" id="v65-v6-lcg"/>
<constraint firstItem="Osf-2d-Znm" firstAttribute="top" secondItem="2QC-6F-Xpx" secondAttribute="bottom" constant="8.5" id="w9V-Ww-OfN"/>
</constraints>
</view>
</stackView>
</subviews>
<constraints>
<constraint firstItem="DMn-tw-NTB" firstAttribute="leading" secondItem="LFJ-SB-Zp9" secondAttribute="leading" id="BTk-bF-S0d"/>
<constraint firstAttribute="trailing" secondItem="DMn-tw-NTB" secondAttribute="trailing" id="M93-XD-94I"/>
<constraint firstItem="DMn-tw-NTB" firstAttribute="width" secondItem="LFJ-SB-Zp9" secondAttribute="width" id="MCM-o2-30q"/>
<constraint firstItem="DMn-tw-NTB" firstAttribute="top" secondItem="LFJ-SB-Zp9" secondAttribute="top" id="QhZ-ly-cBA"/>
<constraint firstAttribute="bottom" secondItem="DMn-tw-NTB" secondAttribute="bottom" id="sFU-Ot-379"/>
<constraint firstAttribute="bottom" secondItem="iBe-qv-i0y" secondAttribute="bottom" id="2eW-ho-pUq"/>
<constraint firstItem="iBe-qv-i0y" firstAttribute="leading" secondItem="LFJ-SB-Zp9" secondAttribute="leading" constant="20" id="3hL-bu-Q3Q"/>
<constraint firstItem="iBe-qv-i0y" firstAttribute="centerX" secondItem="LFJ-SB-Zp9" secondAttribute="centerX" id="CSK-X3-R8W"/>
<constraint firstAttribute="trailing" secondItem="iBe-qv-i0y" secondAttribute="trailing" constant="20" id="hIF-Hy-Smw"/>
<constraint firstItem="iBe-qv-i0y" firstAttribute="top" secondItem="LFJ-SB-Zp9" secondAttribute="top" constant="20" id="v0I-Gh-S3A"/>
</constraints>
</scrollView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="← Swipe Screen Edges in View →" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ma4-O6-wOT">
<rect key="frame" x="87.5" y="643" width="200.5" height="16"/>
<rect key="frame" x="87" y="643" width="201.5" height="16"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@@ -205,14 +242,15 @@
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="LFJ-SB-Zp9" firstAttribute="top" secondItem="0gg-po-Ih1" secondAttribute="topMargin" id="0T7-Dc-CaB"/>
<constraint firstItem="LFJ-SB-Zp9" firstAttribute="leading" secondItem="0gg-po-Ih1" secondAttribute="leading" id="OsA-4z-Y7t"/>
<constraint firstItem="LFJ-SB-Zp9" firstAttribute="leading" secondItem="x7m-y5-rfi" secondAttribute="leading" id="OsA-4z-Y7t"/>
<constraint firstItem="ma4-O6-wOT" firstAttribute="top" secondItem="LFJ-SB-Zp9" secondAttribute="bottom" constant="8" id="UUi-lo-0RA"/>
<constraint firstItem="ma4-O6-wOT" firstAttribute="centerX" secondItem="0gg-po-Ih1" secondAttribute="centerX" id="aia-PT-OH3"/>
<constraint firstItem="LW0-9z-RHu" firstAttribute="top" secondItem="ma4-O6-wOT" secondAttribute="bottom" constant="8" id="d5Q-Sj-0Xz"/>
<constraint firstItem="LFJ-SB-Zp9" firstAttribute="top" secondItem="Rm7-bv-OCN" secondAttribute="bottom" id="ssi-ps-a2k"/>
<constraint firstAttribute="trailing" secondItem="LFJ-SB-Zp9" secondAttribute="trailing" id="t0e-pR-bB1"/>
<constraint firstItem="LFJ-SB-Zp9" firstAttribute="top" secondItem="x7m-y5-rfi" secondAttribute="top" id="W6M-QX-I2w"/>
<constraint firstItem="ma4-O6-wOT" firstAttribute="centerX" secondItem="x7m-y5-rfi" secondAttribute="centerX" id="aia-PT-OH3"/>
<constraint firstItem="x7m-y5-rfi" firstAttribute="bottom" secondItem="ma4-O6-wOT" secondAttribute="bottom" constant="8" id="d5Q-Sj-0Xz"/>
<constraint firstItem="LFJ-SB-Zp9" firstAttribute="top" secondItem="x7m-y5-rfi" secondAttribute="top" id="ssi-ps-a2k"/>
<constraint firstItem="x7m-y5-rfi" firstAttribute="trailing" secondItem="LFJ-SB-Zp9" secondAttribute="trailing" id="t0e-pR-bB1"/>
</constraints>
<viewLayoutGuide key="safeArea" id="x7m-y5-rfi"/>
<variation key="default">
<mask key="constraints">
<exclude reference="ssi-ps-a2k"/>
@@ -235,11 +273,13 @@
<connections>
<outlet property="blackOutStatusBar" destination="oFS-2Q-kPB" id="wrn-ru-xmL"/>
<outlet property="blurSegmentControl" destination="owH-AA-wgw" id="OKW-xQ-7UM"/>
<outlet property="darknessSlider" destination="pqT-4M-nw1" id="Bka-VM-Plx"/>
<outlet property="presentModeSegmentedControl" destination="KV2-tN-Aff" id="dzq-Bi-3Zp"/>
<outlet property="menuAlphaSlider" destination="pqT-4M-nw1" id="X32-tm-KBc"/>
<outlet property="menuScaleFactorSlider" destination="Xp9-C5-Td1" id="gyq-PL-JO7"/>
<outlet property="presentationStyleSegmentedControl" destination="KV2-tN-Aff" id="dzq-Bi-3Zp"/>
<outlet property="presentingAlphaSlider" destination="xlA-NK-mN4" id="Dg9-nd-07P"/>
<outlet property="presentingScaleFactorSlider" destination="Oso-tQ-0MO" id="TVy-sK-3NK"/>
<outlet property="screenWidthSlider" destination="Cor-r1-osR" id="pOL-9d-Weh"/>
<outlet property="shadowOpacitySlider" destination="Osf-2d-Znm" id="6ai-oQ-d06"/>
<outlet property="shrinkFactorSlider" destination="Xp9-C5-Td1" id="i3p-s2-Y9E"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="uVk-3R-pAo" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -249,10 +289,10 @@
<!--Side Menu Navigation Controller-->
<scene sceneID="Zbc-0f-8nT">
<objects>
<navigationController storyboardIdentifier="LeftMenuNavigationController" navigationBarHidden="YES" id="DuX-EW-0mP" customClass="UISideMenuNavigationController" customModule="SideMenu" sceneMemberID="viewController">
<navigationController storyboardIdentifier="LeftMenuNavigationController" navigationBarHidden="YES" id="DuX-EW-0mP" customClass="SideMenuNavigationController" customModule="SideMenu" sceneMemberID="viewController">
<navigationItem key="navigationItem" id="ipz-Lx-Wgf"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="35F-wh-r6h">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<rect key="frame" x="0.0" y="-20" width="0.0" height="0.0"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<userDefinedRuntimeAttributes>
@@ -266,18 +306,18 @@
</objects>
<point key="canvasLocation" x="961.875" y="8.4507042253521121"/>
</scene>
<!--Side Menu Table View-->
<!--Side Menu Table View Controller-->
<scene sceneID="L2w-o7-jEN">
<objects>
<tableViewController id="V6g-oO-Tbm" customClass="SideMenuTableView" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<tableViewController id="V6g-oO-Tbm" customClass="SideMenuTableViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" scrollEnabled="NO" dataMode="static" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="Dqh-bs-m2M">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<color key="tintColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<inset key="separatorInset" minX="15" minY="0.0" maxX="8" maxY="0.0"/>
<view key="tableFooterView" contentMode="scaleToFill" id="vVB-ag-TnU">
<rect key="frame" x="0.0" y="132" width="375" height="0.0"/>
<rect key="frame" x="0.0" y="188" width="375" height="0.0"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
@@ -285,14 +325,14 @@
<tableViewSection id="gP8-eA-dcW">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="4WI-Ed-3Gr" style="IBUITableViewCellStyleDefault" id="7tx-O6-zAs" customClass="UITableViewVibrantCell" customModule="SideMenu">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<rect key="frame" x="0.0" y="28" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="7tx-O6-zAs" id="K0u-J2-Ab7">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Push View Controller 1" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="4WI-Ed-3Gr">
<rect key="frame" x="15" y="0.0" width="345" height="43.5"/>
<rect key="frame" x="16" y="0.0" width="343" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -306,14 +346,14 @@
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="DpJ-hV-lmw" style="IBUITableViewCellStyleDefault" id="f9Q-QP-TZ6" customClass="UITableViewVibrantCell" customModule="SideMenu">
<rect key="frame" x="0.0" y="44" width="375" height="44"/>
<rect key="frame" x="0.0" y="72" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="f9Q-QP-TZ6" id="i3p-Ya-AvO">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Push View Controller 2" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="DpJ-hV-lmw">
<rect key="frame" x="15" y="0.0" width="345" height="43.5"/>
<rect key="frame" x="16" y="0.0" width="343" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -327,14 +367,14 @@
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="mAf-mx-C48" style="IBUITableViewCellStyleDefault" id="dc6-l8-0cu" customClass="UITableViewVibrantCell" customModule="SideMenu">
<rect key="frame" x="0.0" y="88" width="375" height="44"/>
<rect key="frame" x="0.0" y="116" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="dc6-l8-0cu" id="gyo-JQ-fx5">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Push View Controller 3" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="mAf-mx-C48">
<rect key="frame" x="15" y="0.0" width="345" height="43.5"/>
<rect key="frame" x="16" y="0.0" width="343" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -365,14 +405,11 @@
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="PresentedViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="bCi-eF-6hb"/>
<viewControllerLayoutGuide type="bottom" id="WdI-PK-HMg"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.80000001190000003" green="1" blue="0.40000000600000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="tWG-DO-ZIZ"/>
</view>
<navigationItem key="navigationItem" title="You Can Still Swipe!" id="LXz-Eu-D0y">
<barButtonItem key="backBarButtonItem" title=" " id="igL-eY-0yM"/>
@@ -385,9 +422,9 @@
<!--Side Menu Navigation Controller-->
<scene sceneID="kei-0w-mFw">
<objects>
<navigationController storyboardIdentifier="RightMenuNavigationController" navigationBarHidden="YES" id="z7k-fk-pfc" customClass="UISideMenuNavigationController" customModule="SideMenu" sceneMemberID="viewController">
<navigationController storyboardIdentifier="RightMenuNavigationController" navigationBarHidden="YES" id="z7k-fk-pfc" customClass="SideMenuNavigationController" customModule="SideMenu" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="qOd-yQ-2i8">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<rect key="frame" x="0.0" y="-20" width="0.0" height="0.0"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
@@ -398,17 +435,17 @@
</objects>
<point key="canvasLocation" x="961.875" y="698.23943661971828"/>
</scene>
<!--Side Menu Table View-->
<!--Side Menu Table View Controller-->
<scene sceneID="l9t-dY-QwR">
<objects>
<tableViewController id="Ol4-YR-KUL" customClass="SideMenuTableView" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<tableViewController id="Ol4-YR-KUL" customClass="SideMenuTableViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" scrollEnabled="NO" dataMode="static" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="49z-eA-JB7">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<inset key="separatorInset" minX="0.0" minY="0.0" maxX="15" maxY="0.0"/>
<view key="tableFooterView" contentMode="scaleToFill" id="UXT-t2-k90">
<rect key="frame" x="0.0" y="132" width="375" height="0.0"/>
<rect key="frame" x="0.0" y="188" width="375" height="0.0"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
@@ -416,14 +453,14 @@
<tableViewSection id="xTE-WH-UeX">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="NLA-8t-ufi" style="IBUITableViewCellStyleDefault" id="8Ng-b4-4hH" customClass="UITableViewVibrantCell" customModule="SideMenu">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<rect key="frame" x="0.0" y="28" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="8Ng-b4-4hH" id="U5K-l9-XWv">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Present View Controller 1" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="NLA-8t-ufi">
<rect key="frame" x="15" y="0.0" width="345" height="43.5"/>
<rect key="frame" x="16" y="0.0" width="343" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -433,18 +470,18 @@
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<segue destination="uMV-sw-TbB" kind="presentation" id="7VM-K4-IQ0"/>
<segue destination="uMV-sw-TbB" kind="presentation" modalPresentationStyle="fullScreen" id="7VM-K4-IQ0"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="IdU-2D-zHb" style="IBUITableViewCellStyleDefault" id="Eok-gX-LwQ" customClass="UITableViewVibrantCell" customModule="SideMenu">
<rect key="frame" x="0.0" y="44" width="375" height="44"/>
<rect key="frame" x="0.0" y="72" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Eok-gX-LwQ" id="IOJ-bC-bNt">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Present View Controller 2" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="IdU-2D-zHb">
<rect key="frame" x="15" y="0.0" width="345" height="43.5"/>
<rect key="frame" x="16" y="0.0" width="343" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -458,14 +495,14 @@
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="6x7-O7-DkG" style="IBUITableViewCellStyleDefault" id="41i-KK-YM3" customClass="UITableViewVibrantCell" customModule="SideMenu">
<rect key="frame" x="0.0" y="88" width="375" height="44"/>
<rect key="frame" x="0.0" y="116" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="41i-KK-YM3" id="629-G3-Agl">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Present View Controller 3" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6x7-O7-DkG">
<rect key="frame" x="15" y="0.0" width="345" height="43.5"/>
<rect key="frame" x="16" y="0.0" width="343" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -496,10 +533,6 @@
<scene sceneID="1Bw-F8-wcb">
<objects>
<viewController id="uMV-sw-TbB" customClass="PresentedViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="CUv-pn-QnG"/>
<viewControllerLayoutGuide type="bottom" id="Y6o-PP-5OP"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="087-P6-J9s">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -516,12 +549,13 @@
</subviews>
<color key="backgroundColor" red="0.40000000600000002" green="0.80000001190000003" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="Y6o-PP-5OP" firstAttribute="top" secondItem="TJh-vs-sd4" secondAttribute="bottom" id="4Dc-FA-01g"/>
<constraint firstItem="TJh-vs-sd4" firstAttribute="top" secondItem="CUv-pn-QnG" secondAttribute="bottom" id="JJZ-xG-7d7"/>
<constraint firstItem="TSP-pU-CHw" firstAttribute="bottom" secondItem="TJh-vs-sd4" secondAttribute="bottom" id="4Dc-FA-01g"/>
<constraint firstItem="TJh-vs-sd4" firstAttribute="top" secondItem="TSP-pU-CHw" secondAttribute="top" id="JJZ-xG-7d7"/>
<constraint firstItem="TJh-vs-sd4" firstAttribute="top" secondItem="087-P6-J9s" secondAttribute="top" id="UJb-lR-QB7"/>
<constraint firstItem="TJh-vs-sd4" firstAttribute="leading" secondItem="087-P6-J9s" secondAttribute="leading" id="WfV-Kk-KZn"/>
<constraint firstAttribute="trailing" secondItem="TJh-vs-sd4" secondAttribute="trailing" id="nDl-ag-4Xh"/>
<constraint firstItem="TJh-vs-sd4" firstAttribute="leading" secondItem="TSP-pU-CHw" secondAttribute="leading" id="WfV-Kk-KZn"/>
<constraint firstItem="TSP-pU-CHw" firstAttribute="trailing" secondItem="TJh-vs-sd4" secondAttribute="trailing" id="nDl-ag-4Xh"/>
</constraints>
<viewLayoutGuide key="safeArea" id="TSP-pU-CHw"/>
<variation key="default">
<mask key="constraints">
<exclude reference="JJZ-xG-7d7"/>
@@ -538,16 +572,12 @@
<scene sceneID="afw-j1-hgm">
<objects>
<viewController id="Upx-FH-Mbv" customClass="PresentedViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="o4B-82-huU"/>
<viewControllerLayoutGuide type="bottom" id="Cg1-5G-fVh"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="efR-Hd-Gxy">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cKk-fD-whk">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<state key="normal" title="Dismiss">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
@@ -559,11 +589,12 @@
<color key="backgroundColor" red="0.40000000600000002" green="0.40000000600000002" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="cKk-fD-whk" firstAttribute="top" secondItem="efR-Hd-Gxy" secondAttribute="top" id="14o-4k-9wZ"/>
<constraint firstItem="cKk-fD-whk" firstAttribute="leading" secondItem="efR-Hd-Gxy" secondAttribute="leading" id="BI7-Em-0rv"/>
<constraint firstItem="cKk-fD-whk" firstAttribute="top" secondItem="o4B-82-huU" secondAttribute="bottom" id="c7O-I7-GYg"/>
<constraint firstAttribute="trailing" secondItem="cKk-fD-whk" secondAttribute="trailing" id="cQ8-xJ-kZK"/>
<constraint firstItem="Cg1-5G-fVh" firstAttribute="top" secondItem="cKk-fD-whk" secondAttribute="bottom" id="flh-y2-QfX"/>
<constraint firstItem="cKk-fD-whk" firstAttribute="leading" secondItem="BaQ-yt-6sz" secondAttribute="leading" id="BI7-Em-0rv"/>
<constraint firstItem="cKk-fD-whk" firstAttribute="top" secondItem="BaQ-yt-6sz" secondAttribute="top" id="c7O-I7-GYg"/>
<constraint firstItem="BaQ-yt-6sz" firstAttribute="trailing" secondItem="cKk-fD-whk" secondAttribute="trailing" id="cQ8-xJ-kZK"/>
<constraint firstItem="BaQ-yt-6sz" firstAttribute="bottom" secondItem="cKk-fD-whk" secondAttribute="bottom" id="flh-y2-QfX"/>
</constraints>
<viewLayoutGuide key="safeArea" id="BaQ-yt-6sz"/>
<variation key="default">
<mask key="constraints">
<exclude reference="c7O-I7-GYg"/>
@@ -580,16 +611,12 @@
<scene sceneID="lxj-KK-fq7">
<objects>
<viewController id="EG7-2X-5hP" customClass="PresentedViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="hJH-tK-XeV"/>
<viewControllerLayoutGuide type="bottom" id="e3Y-bn-25N"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="vac-ts-bf9">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="a17-pq-WAQ">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<state key="normal" title="Dismiss">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
@@ -600,12 +627,13 @@
</subviews>
<color key="backgroundColor" red="1" green="0.40000000600000002" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="e3Y-bn-25N" firstAttribute="top" secondItem="a17-pq-WAQ" secondAttribute="bottom" id="5xQ-vm-6fc"/>
<constraint firstAttribute="trailing" secondItem="a17-pq-WAQ" secondAttribute="trailing" id="Hxw-zj-3jZ"/>
<constraint firstItem="A8B-VL-gbR" firstAttribute="bottom" secondItem="a17-pq-WAQ" secondAttribute="bottom" id="5xQ-vm-6fc"/>
<constraint firstItem="A8B-VL-gbR" firstAttribute="trailing" secondItem="a17-pq-WAQ" secondAttribute="trailing" id="Hxw-zj-3jZ"/>
<constraint firstItem="a17-pq-WAQ" firstAttribute="top" secondItem="vac-ts-bf9" secondAttribute="topMargin" id="MC9-JY-ajb"/>
<constraint firstItem="a17-pq-WAQ" firstAttribute="leading" secondItem="vac-ts-bf9" secondAttribute="leading" id="v2E-c1-L5X"/>
<constraint firstItem="a17-pq-WAQ" firstAttribute="top" secondItem="hJH-tK-XeV" secondAttribute="bottom" id="zAS-oF-Owc"/>
<constraint firstItem="a17-pq-WAQ" firstAttribute="leading" secondItem="A8B-VL-gbR" secondAttribute="leading" id="v2E-c1-L5X"/>
<constraint firstItem="a17-pq-WAQ" firstAttribute="top" secondItem="A8B-VL-gbR" secondAttribute="top" id="zAS-oF-Owc"/>
</constraints>
<viewLayoutGuide key="safeArea" id="A8B-VL-gbR"/>
<variation key="default">
<mask key="constraints">
<exclude reference="zAS-oF-Owc"/>
@@ -622,14 +650,11 @@
<scene sceneID="6GP-Jo-SOW">
<objects>
<viewController id="u7M-mb-V6o" customClass="PresentedViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="RTd-LU-QPL"/>
<viewControllerLayoutGuide type="bottom" id="MN7-Vy-BNb"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="9Dr-7n-COJ">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="0.80000001190000003" blue="0.40000000600000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="hUi-v8-7VE"/>
</view>
<navigationItem key="navigationItem" title="You Can Still Swipe!" id="I4v-gH-e3M">
<barButtonItem key="backBarButtonItem" title=" " id="csP-tV-uyu"/>
@@ -643,14 +668,11 @@
<scene sceneID="ZQL-2c-L6r">
<objects>
<viewController id="b5t-IX-0yu" customClass="PresentedViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="rfX-xz-c0N"/>
<viewControllerLayoutGuide type="bottom" id="Iuo-on-rwS"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ias-bH-Sau">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="0.40000000600000002" blue="0.40000000600000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="bHF-BB-8F0"/>
</view>
<navigationItem key="navigationItem" title="You Can Still Swipe!" id="VCv-tR-uCt">
<barButtonItem key="backBarButtonItem" title=" " id="Xem-d1-6TQ"/>
+118
View File
@@ -0,0 +1,118 @@
//
// MainViewController.swift
//
// Created by Jon Kent on 11/12/15.
// Copyright © 2015 Jon Kent. All rights reserved.
//
import SideMenu
class MainViewController: UIViewController {
@IBOutlet private weak var blackOutStatusBar: UISwitch!
@IBOutlet private weak var blurSegmentControl: UISegmentedControl!
@IBOutlet private weak var menuAlphaSlider: UISlider!
@IBOutlet private weak var menuScaleFactorSlider: UISlider!
@IBOutlet private weak var presentingAlphaSlider: UISlider!
@IBOutlet private weak var presentingScaleFactorSlider: UISlider!
@IBOutlet private weak var presentationStyleSegmentedControl: UISegmentedControl!
@IBOutlet private weak var screenWidthSlider: UISlider!
@IBOutlet private weak var shadowOpacitySlider: UISlider!
override func viewDidLoad() {
super.viewDidLoad()
setupSideMenu()
updateUI(settings: SideMenuSettings())
updateMenus()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let sideMenuNavigationController = segue.destination as? SideMenuNavigationController else { return }
sideMenuNavigationController.settings = makeSettings()
}
private func setupSideMenu() {
// Define the menus
SideMenuManager.default.leftMenuNavigationController = storyboard?.instantiateViewController(withIdentifier: "LeftMenuNavigationController") as? SideMenuNavigationController
SideMenuManager.default.rightMenuNavigationController = storyboard?.instantiateViewController(withIdentifier: "RightMenuNavigationController") as? SideMenuNavigationController
// Enable gestures. The left and/or right menus must be set up above for these to work.
// Note that these continue to work on the Navigation Controller independent of the View Controller it displays!
SideMenuManager.default.addPanGestureToPresent(toView: navigationController!.navigationBar)
SideMenuManager.default.addScreenEdgePanGesturesToPresent(toView: view)
}
private func updateUI(settings: SideMenuSettings) {
let styles:[UIBlurEffect.Style] = [.dark, .light, .extraLight]
if let menuBlurEffectStyle = settings.blurEffectStyle {
blurSegmentControl.selectedSegmentIndex = (styles.firstIndex(of: menuBlurEffectStyle) ?? 0) + 1
} else {
blurSegmentControl.selectedSegmentIndex = 0
}
blackOutStatusBar.isOn = settings.statusBarEndAlpha > 0
menuAlphaSlider.value = Float(settings.presentationStyle.menuStartAlpha)
menuScaleFactorSlider.value = Float(settings.presentationStyle.menuScaleFactor)
presentingAlphaSlider.value = Float(settings.presentationStyle.presentingEndAlpha)
presentingScaleFactorSlider.value = Float(settings.presentationStyle.presentingScaleFactor)
screenWidthSlider.value = Float(settings.menuWidth / min(view.frame.width, view.frame.height))
shadowOpacitySlider.value = Float(settings.presentationStyle.onTopShadowOpacity)
}
@IBAction private func changeControl(_ control: UIControl) {
if control == presentationStyleSegmentedControl {
var settings = makeSettings()
settings.presentationStyle = selectedPresentationStyle()
updateUI(settings: settings)
}
updateMenus()
}
private func updateMenus() {
let settings = makeSettings()
SideMenuManager.default.leftMenuNavigationController?.settings = settings
SideMenuManager.default.rightMenuNavigationController?.settings = settings
}
private func selectedPresentationStyle() -> SideMenuPresentationStyle {
let modes: [SideMenuPresentationStyle] = [.menuSlideIn, .viewSlideOut, .viewSlideOutMenuIn, .menuDissolveIn]
return modes[presentationStyleSegmentedControl.selectedSegmentIndex]
}
private func makeSettings() -> SideMenuSettings {
let presentationStyle = selectedPresentationStyle()
presentationStyle.backgroundColor = UIColor(patternImage: #imageLiteral(resourceName: "background"))
presentationStyle.menuStartAlpha = CGFloat(menuAlphaSlider.value)
presentationStyle.menuScaleFactor = CGFloat(menuScaleFactorSlider.value)
presentationStyle.onTopShadowOpacity = shadowOpacitySlider.value
presentationStyle.presentingEndAlpha = CGFloat(presentingAlphaSlider.value)
presentationStyle.presentingScaleFactor = CGFloat(presentingScaleFactorSlider.value)
var settings = SideMenuSettings()
settings.presentationStyle = presentationStyle
settings.menuWidth = min(view.frame.width, view.frame.height) * CGFloat(screenWidthSlider.value)
let styles:[UIBlurEffect.Style?] = [nil, .dark, .light, .extraLight]
settings.blurEffectStyle = styles[blurSegmentControl.selectedSegmentIndex]
settings.statusBarEndAlpha = blackOutStatusBar.isOn ? 1 : 0
return settings
}
}
extension MainViewController: SideMenuNavigationControllerDelegate {
func sideMenuWillAppear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Appearing! (animated: \(animated))")
}
func sideMenuDidAppear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Appeared! (animated: \(animated))")
}
func sideMenuWillDisappear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Disappearing! (animated: \(animated))")
}
func sideMenuDidDisappear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Disappeared! (animated: \(animated))")
}
}
@@ -9,8 +9,8 @@ import UIKit
class PresentedViewController: UIViewController {
@IBAction fileprivate func close() {
self.dismiss(animated: true, completion: nil)
@IBAction private func close() {
dismiss(animated: true, completion: nil)
}
}
@@ -0,0 +1,40 @@
//
// SideMenuTableViewController.swift
// SideMenu
//
// Created by Jon Kent on 4/5/16.
// Copyright © 2016 CocoaPods. All rights reserved.
//
import SideMenu
class SideMenuTableViewController: UITableViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// refresh cell blur effect in case it changed
tableView.reloadData()
guard let menu = navigationController as? SideMenuNavigationController, menu.blurEffectStyle == nil else {
return
}
// Set up a cool background image for demo purposes
let imageView = UIImageView(image: #imageLiteral(resourceName: "saturn"))
imageView.contentMode = .scaleAspectFit
imageView.backgroundColor = UIColor.black.withAlphaComponent(0.2)
tableView.backgroundView = imageView
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAt: indexPath) as! UITableViewVibrantCell
if let menu = navigationController as? SideMenuNavigationController {
cell.blurEffectStyle = menu.blurEffectStyle
}
return cell
}
}
+3 -2
View File
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = "SideMenu"
s.version = "2.3.0"
s.version = "6.5.0"
s.summary = "Simple side menu control for iOS in Swift inspired by Facebook. Right and Left sides. No coding required."
# This description is used to generate tags and improve search results.
@@ -28,7 +28,8 @@ Pod::Spec.new do |s|
s.source = { :git => "https://github.com/jonkykong/SideMenu.git", :tag => s.version.to_s }
# s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
s.ios.deployment_target = '8.0'
s.ios.deployment_target = '10.0'
s.swift_version = '5.0'
s.source_files = 'Pod/Classes/**/*'
# s.resource_bundles = {
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0900"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C4A0A7D8591B67FB75E2E8D215E3735B"
BuildableName = "SideMenu.framework"
BlueprintName = "SideMenu"
ReferencedContainer = "container:Pods/Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7B48A0D21DCB2487002990A1"
BuildableName = "Example (UIKit).app"
BlueprintName = "Example (UIKit)"
ReferencedContainer = "container:SideMenu.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7B48A0D21DCB2487002990A1"
BuildableName = "Example (UIKit).app"
BlueprintName = "Example (UIKit)"
ReferencedContainer = "container:SideMenu.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8432CC0022FFBCF4003D2BBD"
BuildableName = "Example (UIKit) Tests.xctest"
BlueprintName = "Example (UIKit) Tests"
ReferencedContainer = "container:SideMenu.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7B48A0D21DCB2487002990A1"
BuildableName = "Example (UIKit).app"
BlueprintName = "Example (UIKit)"
ReferencedContainer = "container:SideMenu.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7B48A0D21DCB2487002990A1"
BuildableName = "Example (UIKit).app"
BlueprintName = "Example (UIKit)"
ReferencedContainer = "container:SideMenu.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0820"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -29,8 +29,6 @@
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -51,8 +49,6 @@
ReferencedContainer = "container:SideMenu.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 135 KiB