Compare commits

...

54 Commits

Author SHA1 Message Date
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
21 changed files with 696 additions and 350 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
+11 -11
View File
@@ -26,14 +26,14 @@ class MainViewController: UIViewController {
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let sideMenuNavigationController = segue.destination as? UISideMenuNavigationController else { return }
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? UISideMenuNavigationController
SideMenuManager.default.rightMenuNavigationController = storyboard?.instantiateViewController(withIdentifier: "RightMenuNavigationController") as? UISideMenuNavigationController
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!
@@ -44,7 +44,7 @@ class MainViewController: UIViewController {
private func updateUI(settings: SideMenuSettings) {
let styles:[UIBlurEffect.Style] = [.dark, .light, .extraLight]
if let menuBlurEffectStyle = settings.blurEffectStyle {
blurSegmentControl.selectedSegmentIndex = styles.firstIndex(of: menuBlurEffectStyle) ?? 0
blurSegmentControl.selectedSegmentIndex = (styles.firstIndex(of: menuBlurEffectStyle) ?? 0) + 1
} else {
blurSegmentControl.selectedSegmentIndex = 0
}
@@ -54,7 +54,7 @@ class MainViewController: UIViewController {
menuScaleFactorSlider.value = Float(settings.presentationStyle.menuScaleFactor)
presentingAlphaSlider.value = Float(settings.presentationStyle.presentingEndAlpha)
presentingScaleFactorSlider.value = Float(settings.presentationStyle.presentingScaleFactor)
screenWidthSlider.value = Float(settings.menuWidth / view.frame.width)
screenWidthSlider.value = Float(settings.menuWidth / min(view.frame.width, view.frame.height))
shadowOpacitySlider.value = Float(settings.presentationStyle.onTopShadowOpacity)
}
@@ -89,7 +89,7 @@ class MainViewController: UIViewController {
var settings = SideMenuSettings()
settings.presentationStyle = presentationStyle
settings.menuWidth = view.frame.width * CGFloat(screenWidthSlider.value)
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
@@ -98,21 +98,21 @@ class MainViewController: UIViewController {
}
}
extension MainViewController: UISideMenuNavigationControllerDelegate {
extension MainViewController: SideMenuNavigationControllerDelegate {
func sideMenuWillAppear(menu: UISideMenuNavigationController, animated: Bool) {
func sideMenuWillAppear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Appearing! (animated: \(animated))")
}
func sideMenuDidAppear(menu: UISideMenuNavigationController, animated: Bool) {
func sideMenuDidAppear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Appeared! (animated: \(animated))")
}
func sideMenuWillDisappear(menu: UISideMenuNavigationController, animated: Bool) {
func sideMenuWillDisappear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Disappearing! (animated: \(animated))")
}
func sideMenuDidDisappear(menu: UISideMenuNavigationController, animated: Bool) {
func sideMenuDidDisappear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Disappeared! (animated: \(animated))")
}
}
+2 -2
View File
@@ -17,7 +17,7 @@ class SideMenuTableViewController: UITableViewController {
// refresh cell blur effect in case it changed
tableView.reloadData()
guard let menu = navigationController as? UISideMenuNavigationController, menu.blurEffectStyle == nil else {
guard let menu = navigationController as? SideMenuNavigationController, menu.blurEffectStyle == nil else {
return
}
@@ -31,7 +31,7 @@ class SideMenuTableViewController: UITableViewController {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAt: indexPath) as! UITableViewVibrantCell
if let menu = navigationController as? UISideMenuNavigationController {
if let menu = navigationController as? SideMenuNavigationController {
cell.blurEffectStyle = menu.blurEffectStyle
}
+82
View File
@@ -0,0 +1,82 @@
//
// 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]
}
private var mainViewControllerNavigation: XCUIElement {
return mainViewController.otherElements[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()
validate()
}
}
func testSwiping() {
mainViewControllerNavigation.swipeRight()
let element = app.children(matching: .window).element(boundBy: 0).children(matching: .other).element
element.swipeLeft()
validate()
element.swipeLeft()
mainViewControllerNavigation.swipeLeft()
element.swipeRight()
validate()
}
private func validate() {
XCTAssertTrue(mainViewController.exists)
}
/* TODO - More tests:
- Rotation
- All menu settings
*/
}
+1 -3
View File
@@ -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>
-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.
}
}
}
+34 -22
View File
@@ -9,54 +9,54 @@
extension SideMenuManager {
@available(*, deprecated, renamed: "leftMenuNavigationController")
open var menuLeftNavigationController: UISideMenuNavigationController? {
open var menuLeftNavigationController: SideMenuNavigationController? {
get { return nil }
set {}
}
@available(*, deprecated, renamed: "rightMenuNavigationController")
open var menuRightNavigationController: UISideMenuNavigationController? {
open var menuRightNavigationController: SideMenuNavigationController? {
get { return nil }
set {}
}
@available(*, deprecated, message: "This property has been moved to the UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuAnimationCompleteGestureDuration: Double {
get { return 0.35 }
set {}
@@ -98,7 +98,7 @@ extension SideMenuManager {
set {}
}
@available(*, deprecated, message: "This property has been moved to the UISideMenuNavigationController class.")
@available(*, deprecated, message: "This property has been moved to the SideMenuNavigationController class.")
public var menuPresentingViewControllerUserInteractionEnabled: Bool {
get { return false }
set {}
@@ -110,78 +110,84 @@ extension SideMenuManager {
set {}
}
@available(*, deprecated, message: "This property has been moved to the UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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 UISideMenuNavigationController class.")
@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
@@ -200,3 +206,9 @@ 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
+14 -1
View File
@@ -46,12 +46,25 @@ internal extension UIViewController {
}
}
// Indicates if the menu is anywhere in the view hierarchy, even if covered by another view controller.
@objc var isHidden: Bool {
return presentingViewController == nil
}
}
internal extension UIGestureRecognizer {
convenience init(addTo view: UIView, target: Any, action: Selector) {
self.init()
addTarget(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)
}
}
internal extension UIPanGestureRecognizer {
var canSwitch: Bool {
+4 -3
View File
@@ -10,8 +10,8 @@ import Foundation
internal protocol InitializableClass: class {
init()
}
extension InitializableClass {
extension InitializableClass {
init(_ block: (Self) -> Void) {
self.init()
block(self)
@@ -23,10 +23,11 @@ extension InitializableClass {
}
}
internal protocol InitializableStruct {
public protocol InitializableStruct {
init()
}
internal extension InitializableStruct {
public extension InitializableStruct {
init(_ block: (inout Self) -> Void) {
self.init()
block(&self)
+4 -2
View File
@@ -28,8 +28,10 @@ internal protocol MenuModel: TransitionModel {
var dismissOnRotation: Bool { get }
/// Automatically dismisses the menu when app goes to the background.
var dismissWhenBackgrounded: Bool { get }
/// Enable or disable gestures that would swipe to dismiss the menu. Default is true.
var enableSwipeGestures: 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.
+15 -7
View File
@@ -9,26 +9,34 @@ 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! UISideMenuNavigationController 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 UISideMenuNavigationController instead of existing instances to avoid crashes if the menu is presented more than once.",
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.",
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."
internal static func warning(_ print: Print, arguments: CVarArg..., required: Bool = false) {
warning(String(format: print.rawValue, arguments), required: required)
enum PropertyName: String { case
leftSide
}
internal static func warning(_ print: Print, required: Bool = false) {
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 {
private static func warning(_ message: String, required: Bool = false) {
static func warning(_ message: String, required: Bool = false) {
let message = "SideMenu Warning: \(message)"
if required {
+6 -20
View File
@@ -9,32 +9,18 @@ import Foundation
internal final class Protected<T: Equatable> {
typealias ConditionBlock = (T) -> Bool
typealias Block = (T) -> Void
typealias ConditionBlock = (_ oldValue: T, T) -> T
private var _value: T
private var conditionBlock: ConditionBlock
private var thenBlock: Block?
private var elseBlock: Block?
private var condition: ConditionBlock
public var value: T {
get {
return _value
}
set {
guard conditionBlock(_value) else {
elseBlock?(_value)
return
}
_value = newValue
thenBlock?(_value)
}
get { return _value }
set { _value = condition(_value, newValue) }
}
init(_ value: T, if conditionBlock: @escaping ConditionBlock, then thenBlock: Block? = nil, else elseBlock: Block? = nil) {
init(_ value: T, when condition: @escaping ConditionBlock) {
self._value = value
self.conditionBlock = conditionBlock
self.thenBlock = thenBlock
self.elseBlock = elseBlock
self.condition = condition
}
}
+30 -24
View File
@@ -30,21 +30,14 @@ public class SideMenuManager: NSObject {
var name: String {
switch self {
case .left: return "menuLeftNavigationController"
case .right: return "menuRightNavigationController"
case .left: return "leftMenuNavigationController"
case .right: return "rightMenuNavigationController"
}
}
}
private var _leftMenu: Protected<Menu?> =
Protected(nil,
if: { $0?.isHidden != false },
else: { _ in Print.warning(.menuInUse, arguments: PresentDirection.left.name, required: true) } )
private var _rightMenu: Protected<Menu?> =
Protected(nil,
if: { $0?.isHidden != false },
else: { _ in Print.warning(.menuInUse, arguments: PresentDirection.right.name, required: true) } )
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) }
private var switching: Bool = false
@@ -57,14 +50,24 @@ public class SideMenuManager: NSObject {
}
/// The left menu.
open var leftMenuNavigationController: UISideMenuNavigationController? {
get { return _leftMenu.value }
open var leftMenuNavigationController: SideMenuNavigationController? {
get {
if _leftMenu.value?.isHidden == true {
_leftMenu.value?.leftSide = true
}
return _leftMenu.value
}
set(menu) { _leftMenu.value = menu }
}
/// The right menu.
open var rightMenuNavigationController: UISideMenuNavigationController? {
get { return _rightMenu.value }
open var rightMenuNavigationController: SideMenuNavigationController? {
get {
if _rightMenu.value?.isHidden == true {
_rightMenu.value?.leftSide = false
}
return _rightMenu.value
}
set(menu) { _rightMenu.value = menu }
}
@@ -123,6 +126,14 @@ internal extension SideMenuManager {
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 {
@@ -193,10 +204,8 @@ private extension SideMenuManager {
screenEdgeGestureRecognizer.edges == edge {
view.removeGestureRecognizer(screenEdgeGestureRecognizer)
}
return SideMenuScreenEdgeGestureRecognizer {
return SideMenuScreenEdgeGestureRecognizer(addTo: view, target: self, action: #selector(handlePresentMenuScreenEdge(_:))).with {
$0.edges = edge
$0.addTarget(self, action: #selector(handlePresentMenuScreenEdge(_:)))
view.addGestureRecognizer($0)
}
}
@@ -204,18 +213,15 @@ private extension SideMenuManager {
if let panGestureRecognizer = view.gestureRecognizers?.first(where: { $0 is SideMenuPanGestureRecognizer }) as? SideMenuPanGestureRecognizer {
return panGestureRecognizer
}
return SideMenuPanGestureRecognizer {
$0.addTarget(self, action: #selector(handlePresentMenuPan(_:)))
view.addGestureRecognizer($0)
}
return SideMenuPanGestureRecognizer(addTo: view, target: self, action: #selector(handlePresentMenuPan(_:)))
}
private var activeViewController: UIViewController? {
var activeViewController: UIViewController? {
return UIApplication.shared.keyWindow?.rootViewController?.activeViewController
}
}
extension SideMenuManager: UISideMenuNavigationControllerTransitionDelegate {
extension SideMenuManager: SideMenuNavigationControllerTransitionDelegate {
internal func sideMenuTransitionDidDismiss(menu: Menu) {
defer { switching = false }
@@ -1,5 +1,5 @@
//
// UISideMenuNavigationController.swift
// SideMenuNavigationController.swift
//
// Created by Jon Kent on 1/14/16.
// Copyright © 2016 Jon Kent. All rights reserved.
@@ -16,18 +16,18 @@ import UIKit
subMenu
}
@objc public protocol UISideMenuNavigationControllerDelegate {
@objc optional func sideMenuWillAppear(menu: UISideMenuNavigationController, animated: Bool)
@objc optional func sideMenuDidAppear(menu: UISideMenuNavigationController, animated: Bool)
@objc optional func sideMenuWillDisappear(menu: UISideMenuNavigationController, animated: Bool)
@objc optional func sideMenuDidDisappear(menu: UISideMenuNavigationController, animated: Bool)
@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 UISideMenuNavigationControllerTransitionDelegate: class {
internal protocol SideMenuNavigationControllerTransitionDelegate: class {
func sideMenuTransitionDidDismiss(menu: Menu)
}
public struct SideMenuSettings: MenuModel {
public struct SideMenuSettings: MenuModel, InitializableStruct {
public var allowPushOfSameClassTwice: Bool = true
public var alwaysAnimate: Bool = true
public var animationOptions: UIView.AnimationOptions = .curveEaseInOut
@@ -39,7 +39,8 @@ public struct SideMenuSettings: MenuModel {
public var dismissOnPush: Bool = true
public var dismissOnRotation: Bool = true
public var dismissWhenBackgrounded: Bool = true
public var enableSwipeGestures: 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
@@ -55,26 +56,21 @@ public struct SideMenuSettings: MenuModel {
public var usingSpringWithDamping: CGFloat = 1
public init() {}
public init(_ block: (inout SideMenuSettings) -> Void) {
self.init()
block(&self)
}
}
internal typealias Menu = UISideMenuNavigationController
internal typealias Menu = SideMenuNavigationController
@objcMembers
open class UISideMenuNavigationController: UINavigationController {
open class SideMenuNavigationController: UINavigationController {
private enum PropertyName: String { case
leftSide
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 lazy var _leftSide = Protected(false,
if: { [weak self] _ in self?.isHidden != false },
else: { _ in Menu.elseCondition(.leftSide) } )
private weak var _sideMenuManager: SideMenuManager?
private weak var foundViewController: UIViewController?
private weak var interactionController: SideMenuInteractionController?
@@ -83,11 +79,13 @@ open class UISideMenuNavigationController: UINavigationController {
private var rotating: Bool = false
private var transitionController: SideMenuTransitionController?
/// Delegate for receiving appear and disappear related events. If `nil` the visible view controller that displays a `UISideMenuNavigationController` automatically receives these events.
internal weak var sideMenuDelegate: UISideMenuNavigationControllerDelegate?
/// Delegate for receiving appear and disappear related events. If `nil` the visible view controller that displays a `SideMenuNavigationController` automatically receives these events.
internal weak var sideMenuDelegate: SideMenuNavigationControllerDelegate?
/// The swipe to dismiss gesture.
private(set) weak var swipeToDismissGesture: UIPanGestureRecognizer? = nil
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 }
@@ -106,9 +104,12 @@ open class UISideMenuNavigationController: UINavigationController {
open var settings = SideMenuSettings() {
didSet {
setupBlur()
if !enableSwipeGestures {
if !enableSwipeToDismissGesture {
removeSwipeGesture()
}
if !enableTapToDismissGesture {
removeTapGesture()
}
}
}
@@ -164,24 +165,28 @@ open class UISideMenuNavigationController: UINavigationController {
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 dismissOnPresent && !isBeingDismissed {
// 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 let presentingView = presentingViewController?.view, let containerView = presentingView.superview {
containerView.addSubview(view)
}
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
}, complete: false, completion: { [weak self] _ in
guard let self = self else { return }
self.activeDelegate?.sideMenuDidDisappear?(menu: self, animated: animated)
self.view.isHidden = true
})
} else {
activeDelegate?.sideMenuWillDisappear?(menu: self, animated: animated)
}
}
@@ -206,11 +211,10 @@ open class UISideMenuNavigationController: UINavigationController {
activeDelegate?.sideMenuDidDisappear?(menu: self, animated: animated)
if dismissOnPresent && !isBeingDismissed {
view.isHidden = true
} else {
if isBeingDismissed {
transitionController = nil
interactive = false
} else if dismissOnPresent {
view.isHidden = true
}
}
@@ -237,15 +241,84 @@ open class UISideMenuNavigationController: UINavigationController {
self.rotating = false
}
}
open override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
transitionController?.layout()
}
override open func pushViewController(_ viewController: UIViewController, animated: Bool) {
let push = shouldPushViewController(viewController: viewController, animated: animated) { [weak self] _ in
self?.foundViewController = nil
guard viewControllers.count > 0 && pushStyle != .subMenu 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)
}
if push {
super.pushViewController(viewController, animated: animated)
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 {
return Print.warning(.cannotPush, arguments: String(describing: potentialNavigationController.self), required: true)
}
// 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() }
if dismissOnPush {
let animated = animated || alwaysAnimate
if animated {
let areAnimationsEnabled = UIView.areAnimationsEnabled
UIView.setAnimationsEnabled(true)
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
})
UIView.setAnimationsEnabled(areAnimationsEnabled)
}
}
if let lastViewController = navigationController.viewControllers.last,
!allowPushOfSameClassTwice && type(of: lastViewController) == type(of: viewController) {
return
}
switch pushStyle {
case .subMenu: return // handled earlier
case .default: break
case .popWhenPossible:
for subViewController in navigationController.viewControllers.reversed() {
if type(of: subViewController) == type(of: viewController) {
navigationController.popToViewController(subViewController, animated: animated)
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 pushStyle == .preserveAndHideBackButton {
preservedViewController.navigationItem.hidesBackButton = true
}
viewControllers.append(preservedViewController)
return navigationController.setViewControllers(viewControllers, animated: animated)
}
if pushStyle == .preserveAndHideBackButton {
viewController.navigationItem.hidesBackButton = true
}
case .replace:
viewController.navigationItem.hidesBackButton = true
return navigationController.setViewControllers([viewController], animated: animated)
}
navigationController.pushViewController(viewController, animated: animated)
}
override open var transitioningDelegate: UIViewControllerTransitioningDelegate? {
@@ -255,7 +328,7 @@ open class UISideMenuNavigationController: UINavigationController {
}
// Interface
extension UISideMenuNavigationController: MenuModel {
extension SideMenuNavigationController: MenuModel {
@IBInspectable open var allowPushOfSameClassTwice: Bool {
get { return settings.allowPushOfSameClassTwice }
@@ -312,9 +385,14 @@ extension UISideMenuNavigationController: MenuModel {
set { settings.dismissWhenBackgrounded = newValue }
}
@IBInspectable open var enableSwipeGestures: Bool {
get { return settings.enableSwipeGestures }
set { settings.enableSwipeGestures = 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 {
@@ -327,6 +405,11 @@ extension UISideMenuNavigationController: MenuModel {
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 }
@@ -370,7 +453,7 @@ extension UISideMenuNavigationController: MenuModel {
}
// IMPORTANT: These methods must be declared open or they will not be called.
extension UISideMenuNavigationController: UIViewControllerTransitioningDelegate {
extension SideMenuNavigationController: UIViewControllerTransitioningDelegate {
open func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
transitionController = SideMenuTransitionController(
@@ -394,13 +477,14 @@ extension UISideMenuNavigationController: UIViewControllerTransitioningDelegate
private func interactionController(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
guard interactive else { return nil }
interactive = false
let interactionController = SideMenuInteractionController(cancelWhenBackgrounded: dismissWhenBackgrounded, completionCurve: completionCurve)
self.interactionController = interactionController
return interactionController
}
}
extension UISideMenuNavigationController: SideMenuTransitionControllerDelegate {
extension SideMenuNavigationController: SideMenuTransitionControllerDelegate {
internal func sideMenuTransitionController(_ transitionController: SideMenuTransitionController, didDismiss viewController: UIViewController) {
sideMenuManager.sideMenuTransitionDidDismiss(menu: self)
@@ -408,16 +492,12 @@ extension UISideMenuNavigationController: SideMenuTransitionControllerDelegate {
internal func sideMenuTransitionController(_ transitionController: SideMenuTransitionController, didPresent viewController: UIViewController) {
removeSwipeGesture()
swipeToDismissGesture = addDismissPanGesture(to: view.superview)
let tapGestureRecognizer = UITapGestureRecognizer()
tapGestureRecognizer.addTarget(self, action: #selector(handleDismissMenuTap(_:)))
tapGestureRecognizer.cancelsTouchesInView = false
view.superview?.addGestureRecognizer(tapGestureRecognizer)
swipeToDismissGesture = addSwipeToDismissGesture(to: view.superview)
tapToDismissGesture = addTapToDismissGesture(to: view.superview)
}
}
internal extension UISideMenuNavigationController {
internal extension SideMenuNavigationController {
func handleMenuPan(_ gesture: UIPanGestureRecognizer, _ presenting: Bool) {
let width = menuWidth
@@ -458,101 +538,14 @@ internal extension UISideMenuNavigationController {
}
}
private extension UISideMenuNavigationController {
private extension SideMenuNavigationController {
func shouldPushViewController(viewController: UIViewController, animated: Bool, completion: ((Bool) -> Void)?) -> Bool {
guard viewControllers.count > 0 && pushStyle != .subMenu else {
// NOTE: pushViewController is called by init(rootViewController: UIViewController)
// so we must perform the normal super method in this case
return true
}
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() }
var push = false
if dismissOnPush {
let animated = animated || alwaysAnimate
if animated {
let areAnimationsEnabled = UIView.areAnimationsEnabled
UIView.setAnimationsEnabled(true)
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)
completion?(push)
})
UIView.setAnimationsEnabled(areAnimationsEnabled)
}
}
if let lastViewController = navigationController.viewControllers.last,
!allowPushOfSameClassTwice && type(of: lastViewController) == type(of: viewController) {
return false
}
switch pushStyle {
case .subMenu: return false // handled earlier
case .default:
navigationController.pushViewController(viewController, animated: animated)
return false
case .popWhenPossible:
for subViewController in navigationController.viewControllers.reversed() {
if type(of: subViewController) == type(of: viewController) {
navigationController.popToViewController(subViewController, animated: animated)
return false
}
}
push = true
return true
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 pushStyle == .preserveAndHideBackButton {
preservedViewController.navigationItem.hidesBackButton = true
}
viewControllers.append(preservedViewController)
navigationController.setViewControllers(viewControllers, animated: animated)
return false
}
if pushStyle == .preserveAndHideBackButton {
viewController.navigationItem.hidesBackButton = true
}
push = true
return true
case .replace:
viewController.navigationItem.hidesBackButton = true
navigationController.setViewControllers([viewController], animated: animated)
return false
}
}
private class func elseCondition(_ propertyName: PropertyName) {
Print.warning(.property, arguments: propertyName.rawValue, required: true)
}
weak var activeDelegate: UISideMenuNavigationControllerDelegate? {
weak var activeDelegate: SideMenuNavigationControllerDelegate? {
guard !view.isHidden else { return nil }
if let sideMenuDelegate = sideMenuDelegate {
return sideMenuDelegate
}
return visibleViewController(from: presentingViewController) as? UISideMenuNavigationControllerDelegate
return visibleViewController(from: presentingViewController) as? SideMenuNavigationControllerDelegate
}
func visibleViewController(from: UIViewController?) -> UIViewController? {
@@ -629,6 +622,12 @@ private extension UISideMenuNavigationController {
}
}
func removeTapGesture() {
if let tapToDismissGesture = tapToDismissGesture {
tapToDismissGesture.view?.removeGestureRecognizer(tapToDismissGesture)
}
}
func registerForNotifications() {
NotificationCenter.default.removeObserver(self)
@@ -655,17 +654,23 @@ private extension UISideMenuNavigationController {
}
}
@discardableResult func addDismissPanGesture(to view: UIView?) -> UIPanGestureRecognizer? {
guard enableSwipeGestures, let view = view else { return nil }
return UIPanGestureRecognizer {
@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
$0.addTarget(self, action: #selector(handleDismissMenuPan(_:)))
view.addGestureRecognizer($0)
}
}
@objc func handleDismissMenuTap(_ tap: UITapGestureRecognizer) {
guard view.window?.hitTest(tap.location(in: nil), with: nil) == view.superview else { return }
let hitTest = view.window?.hitTest(tap.location(in: view.superview), with: nil)
guard hitTest == view.superview else { return }
dismissMenu()
}
+2 -7
View File
@@ -8,7 +8,7 @@
import Foundation
@objcMembers
open class SideMenuPresentationStyle {
open class SideMenuPresentationStyle: InitializableClass {
/// Background color behind the views and status bar color
public var backgroundColor: UIColor = .black
/// The starting alpha value of the menu before it appears
@@ -36,12 +36,7 @@ open class SideMenuPresentationStyle {
/// The strength of the parallax effect on the presenting view once the menu is displayed.
public var presentingParallaxStrength: CGSize = .zero
public init() {}
public convenience init(_ block: (SideMenuPresentationStyle) -> Void) {
self.init()
block(self)
}
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.
func presentationTransitionWillBegin(to presentedViewController: UIViewController, from presentingViewController: UIViewController) {}
+4 -4
View File
@@ -7,7 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
032FEB01E4C88E7C87032FCF9780FC7C /* UISideMenuNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F8B09C72B577EFDB20A3EFF4F0C668A /* UISideMenuNavigationController.swift */; };
032FEB01E4C88E7C87032FCF9780FC7C /* SideMenuNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F8B09C72B577EFDB20A3EFF4F0C668A /* SideMenuNavigationController.swift */; };
0D2D410A6087D4E0A54642165913EF30 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F10B146FA49E99D07F0FA0E38ABE8F /* Models.swift */; };
0F9F3CABB81269CF711A73BAD21E7976 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3212113385A8FBBDB272BD23C409FF61 /* Foundation.framework */; };
287FA1360FD3EF72D700C54856C685C1 /* SideMenuManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FE7B8C8447DD35D435B2AF4A23E221C /* SideMenuManager.swift */; };
@@ -59,7 +59,7 @@
61AFB3209BCB97295281AC6437FB346B /* SideMenuPresentationController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SideMenuPresentationController.swift; path = Pod/Classes/SideMenuPresentationController.swift; sourceTree = "<group>"; };
7825A90E082A1582EB16256B0E722B3F /* Pods-Example-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Example-umbrella.h"; sourceTree = "<group>"; };
8428210022E0448700C6F2D8 /* Deprecations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Deprecations.swift; path = Pod/Classes/Deprecations.swift; sourceTree = "<group>"; };
8F8B09C72B577EFDB20A3EFF4F0C668A /* UISideMenuNavigationController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UISideMenuNavigationController.swift; path = Pod/Classes/UISideMenuNavigationController.swift; sourceTree = "<group>"; };
8F8B09C72B577EFDB20A3EFF4F0C668A /* SideMenuNavigationController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SideMenuNavigationController.swift; path = Pod/Classes/SideMenuNavigationController.swift; sourceTree = "<group>"; };
9CF977D7FB42D367F2810037EBA59B7D /* SideMenu-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SideMenu-dummy.m"; sourceTree = "<group>"; };
9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
AB64592703EA9A196B5C0F07BA1A918A /* SideMenuInteractionController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SideMenuInteractionController.swift; path = Pod/Classes/SideMenuInteractionController.swift; sourceTree = "<group>"; };
@@ -148,7 +148,7 @@
61AFB3209BCB97295281AC6437FB346B /* SideMenuPresentationController.swift */,
D154DB98A04C7BD96E4EFBBD3FE0008A /* SideMenuPresentationStyle.swift */,
30C3188EE68841BE36716860BE079AF8 /* SideMenuTransitionController.swift */,
8F8B09C72B577EFDB20A3EFF4F0C668A /* UISideMenuNavigationController.swift */,
8F8B09C72B577EFDB20A3EFF4F0C668A /* SideMenuNavigationController.swift */,
3ACA278071ED85D04DA83677D6C60528 /* UITableViewVibrantCell.swift */,
);
name = SideMenu;
@@ -337,7 +337,7 @@
614FC39555CB129D97FC24B2D953A427 /* SideMenuPresentationController.swift in Sources */,
D0B45D0F0E7B359807CAFB744FB80CE4 /* SideMenuPresentationStyle.swift in Sources */,
FCBFE25630B6309DF3213AE0F6F34D1A /* SideMenuTransitionController.swift in Sources */,
032FEB01E4C88E7C87032FCF9780FC7C /* UISideMenuNavigationController.swift in Sources */,
032FEB01E4C88E7C87032FCF9780FC7C /* SideMenuNavigationController.swift in Sources */,
45A647715262A70BB9F2F4E7C1439C58 /* UITableViewVibrantCell.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
+44 -41
View File
@@ -1,4 +1,5 @@
# ▤ 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)
@@ -23,8 +24,8 @@
* [Code Implementation](#code-implementation)
* **[Customization](#customization)**
* [SideMenuManager](#sidemenumanager)
* [UISideMenuNavigationController](#uisidemenunavigationcontroller)
* [UISideMenuNavigationControllerDelegate](#uisidemenunavigationcontrollerdelegate)
* [SideMenuNavigationController](#sidemenunavigationcontroller)
* [SideMenuNavigationControllerDelegate](#sidemenunavigationcontrollerdelegate)
* [Advanced](#advanced)
* [Known Issues](#known-issues)
* [Thank You](#thank-you)
@@ -72,10 +73,10 @@ use_frameworks!
pod 'SideMenu'
# For Swift 5 use:
# pod 'SideMenu', '~> 6.0.0'
# pod 'SideMenu', '~> 6.0'
# For Swift 4.2 (no longer maintained) use:
# pod 'SideMenu', '~> 5.0.0'
# pod 'SideMenu', '~> 5.0'
```
Then, run the following command:
@@ -103,10 +104,10 @@ github "jonkykong/SideMenu" "master"
## 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.
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.
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.
@@ -122,10 +123,10 @@ import SideMenu
From a button, do something like this:
``` swift
// Define the menu
let menu = UISideMenuNavigationController(rootViewController: YourViewController)
// UISideMenuNavigationController is a subclass of UINavigationController, so do any additional configuration
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! UISideMenuNavigationController
// let menu = storyboard!.instantiateViewController(withIdentifier: "RightMenu") as! SideMenuNavigationController
present(menu, animated: true, completion: nil)
```
@@ -137,11 +138,11 @@ 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)
SideMenuManager.default.menuLeftNavigationController = menuLeftNavigationController
let leftMenuNavigationController = SideMenuNavigationController(rootViewController: YourViewController)
SideMenuManager.default.leftMenuNavigationController = leftMenuNavigationController
let menuRightNavigationController = UISideMenuNavigationController(rootViewController: YourViewController)
SideMenuManager.default.menuRightNavigationController = menuRightNavigationController
let rightMenuNavigationController = SideMenuNavigationController(rootViewController: YourViewController)
SideMenuManager.default.rightMenuNavigationController = rightMenuNavigationController
// 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!
@@ -149,9 +150,9 @@ SideMenuManager.default.addPanGestureToPresent(toView: self.navigationController
SideMenuManager.default.addScreenEdgePanGesturesToPresent(toView: self.navigationController!.view)
// (Optional) Prevent status bar area from turning black when menu appears:
menuLeftNavigationController.statusBarEndAlpha = 0
leftMenuNavigationController.statusBarEndAlpha = 0
// Copy all settings to the other menu
menuRightNavigationController.settings = menuLeftNavigationController.settings
rightMenuNavigationController.settings = leftMenuNavigationController.settings
```
That's it.
### Customization
@@ -159,9 +160,9 @@ That's it.
`SideMenuManager` supports the following:
``` swift
/// The left menu.
open var menuLeftNavigationController: UISideMenuNavigationController?
open var leftMenuNavigationController: SideMenuNavigationController?
/// The right menu.
public var menuRightNavigationController: UISideMenuNavigationController?
public var rightMenuNavigationController: SideMenuNavigationController?
/**
Adds screen edge gestures for both left and right sides to a view to present a menu.
@@ -188,8 +189,8 @@ public var menuRightNavigationController: UISideMenuNavigationController?
*/
@discardableResult public func addPanGestureToPresent(toView view: UIView) -> UIPanGestureRecognizer
```
#### UISideMenuNavigationController
`UISideMenuNavigationController` supports the following:
#### 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
@@ -217,8 +218,10 @@ var dismissOnPush: Bool = true
var dismissOnRotation: Bool = true
/// Automatically dismisses the menu when app goes to the background.
var dismissWhenBackgrounded: Bool = true
/// Enable or disable gestures that would swipe to dismiss the menu. Default is true.
var enableSwipeGestures: 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.
@@ -256,45 +259,45 @@ var isHidden: Bool
There are 8 pre-defined `SideMenuPresentStyle` options:
``` swift
/// Menu slides in over the existing view.
static let menuSlideIn = SideMenuPresentStyle
static let menuSlideIn: SideMenuPresentStyle
/// The existing view slides out to reveal the menu underneath.
static let viewSlideOut = SideMenuPresentStyle
static let viewSlideOut: SideMenuPresentStyle
/// The existing view slides out while the menu slides in.
static let viewSlideOutMenuIn = SideMenuPresentStyle
static let viewSlideOutMenuIn: SideMenuPresentStyle
/// The menu dissolves in over the existing view.
static let menuDissolveIn = SideMenuPresentStyle
static let menuDissolveIn: SideMenuPresentStyle
/// The existing view slides out while the menu partially slides in.
static let viewSlideOutMenuPartialIn = SideMenuPresentStyle
static let viewSlideOutMenuPartialIn: SideMenuPresentStyle
/// The existing view slides out while the menu slides out from under it.
static let viewSlideOutMenuOut = SideMenuPresentStyle
static let viewSlideOutMenuOut: SideMenuPresentStyle
/// The existing view slides out while the menu partially slides out from under it.
static let viewSlideOutMenuPartialOut = SideMenuPresentStyle
static let viewSlideOutMenuPartialOut: SideMenuPresentStyle
/// The existing view slides out and shrinks to reveal the menu underneath.
static let viewSlideOutMenuZoom = SideMenuPresentStyle
static let viewSlideOutMenuZoom: SideMenuPresentStyle
```
#### UISideMenuNavigationControllerDelegate
To receive notifications when a menu is displayed from a view controller, have it adhere to the `UISideMenuNavigationControllerDelegate` protocol:
#### SideMenuNavigationControllerDelegate
To receive notifications when a menu is displayed from a view controller, have it adhere to the `SideMenuNavigationControllerDelegate` protocol:
``` swift
extension MyViewController: UISideMenuNavigationControllerDelegate {
extension MyViewController: SideMenuNavigationControllerDelegate {
func sideMenuWillAppear(menu: UISideMenuNavigationController, animated: Bool) {
func sideMenuWillAppear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Appearing! (animated: \(animated))")
}
func sideMenuDidAppear(menu: UISideMenuNavigationController, animated: Bool) {
func sideMenuDidAppear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Appeared! (animated: \(animated))")
}
func sideMenuWillDisappear(menu: UISideMenuNavigationController, animated: Bool) {
func sideMenuWillDisappear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Disappearing! (animated: \(animated))")
}
func sideMenuDidDisappear(menu: UISideMenuNavigationController, animated: Bool) {
func sideMenuDidDisappear(menu: SideMenuNavigationController, animated: Bool) {
print("SideMenu Disappeared! (animated: \(animated))")
}
}
```
*Note: setting the `sideMenuDelegate` property on `UISideMenuNavigationController` is optional. If your view controller adheres to the protocol then the methods will be called automatically.*
*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>
@@ -306,9 +309,9 @@ For simplicity, `SideMenuManager.default` serves as the primary instance as most
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 `UISideMenuNavigationController` and set its `sideMenuManager` property to your custom instance. This must be done before `viewDidLoad` is called:
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: UISideMenuNavigationController {
class MySideMenuNavigationController: SideMenuNavigationController {
let customSideMenuManager = SideMenuManager()
@@ -319,10 +322,10 @@ class MySideMenuNavigationController: UISideMenuNavigationController {
}
}
```
Alternatively, you can set `sideMenuManager` from the view controller that segues to your UISideMenuNavigationController:
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? UISideMenuNavigationController {
if let sideMenuNavigationController = segue.destination as? SideMenuNavigationController {
sideMenuNavigationController.sideMenuManager = customSideMenuManager
}
}
+2 -2
View File
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = "SideMenu"
s.version = "6.0.6"
s.version = "6.2.1"
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.
@@ -29,7 +29,7 @@ Pod::Spec.new do |s|
# s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
s.ios.deployment_target = '10.0'
s.swift_version = '5'
s.swift_version = '5.0'
s.source_files = 'Pod/Classes/**/*'
# s.resource_bundles = {
+141 -17
View File
@@ -26,7 +26,8 @@
842820FD22DDD21100C6F2D8 /* SideMenuPresentationStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842820FC22DDD21100C6F2D8 /* SideMenuPresentationStyle.swift */; };
842820FF22DDD24200C6F2D8 /* SideMenuInteractionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842820FE22DDD24200C6F2D8 /* SideMenuInteractionController.swift */; };
8428210322E0449300C6F2D8 /* Deprecations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8428210222E0449300C6F2D8 /* Deprecations.swift */; };
8461A2D51E145A08001DA4F8 /* UISideMenuNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8461A2D11E145A08001DA4F8 /* UISideMenuNavigationController.swift */; };
8432CC0422FFBCF5003D2BBD /* ExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8432CC0322FFBCF5003D2BBD /* ExampleTests.swift */; };
8461A2D51E145A08001DA4F8 /* SideMenuNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8461A2D11E145A08001DA4F8 /* SideMenuNavigationController.swift */; };
8461A2D61E145A08001DA4F8 /* UITableViewVibrantCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8461A2D21E145A08001DA4F8 /* UITableViewVibrantCell.swift */; };
84B489B51DD469B000D6CB43 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 84B489B21DD469B000D6CB43 /* LICENSE */; };
84B489B71DD469B000D6CB43 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 84B489B41DD469B000D6CB43 /* README.md */; };
@@ -34,6 +35,16 @@
ACD6DAED90DE36FEA68CDF38 /* Pods_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47896ABC5C8830D88945A8D3 /* Pods_Example.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
8432CC0622FFBCF5003D2BBD /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 7B9DC8FB1DC6E8C1000D4007 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 7B48A0D21DCB2487002990A1;
remoteInfo = Example;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
1F17B9D56ADA958C611FAA83 /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = "<group>"; };
281FB58A39C022692CEEBF0D /* Pods-Example-ExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example-ExampleTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example-ExampleTests/Pods-Example-ExampleTests.debug.xcconfig"; sourceTree = "<group>"; };
@@ -44,8 +55,6 @@
7B48A0D51DCB2487002990A1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7B48A0DC1DCB2487002990A1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
7B48A0E11DCB2487002990A1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
7B48A0EA1DCB2487002990A1 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = "<group>"; };
7B48A0EC1DCB2487002990A1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
7B48A0F31DCB2518002990A1 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
7B48A0F41DCB2518002990A1 /* PresentedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentedViewController.swift; sourceTree = "<group>"; };
7B48A0F51DCB2518002990A1 /* SideMenuTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SideMenuTableViewController.swift; sourceTree = "<group>"; };
@@ -63,7 +72,10 @@
842820FC22DDD21100C6F2D8 /* SideMenuPresentationStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SideMenuPresentationStyle.swift; path = Pod/Classes/SideMenuPresentationStyle.swift; sourceTree = "<group>"; };
842820FE22DDD24200C6F2D8 /* SideMenuInteractionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SideMenuInteractionController.swift; path = Pod/Classes/SideMenuInteractionController.swift; sourceTree = "<group>"; };
8428210222E0449300C6F2D8 /* Deprecations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Deprecations.swift; path = Pod/Classes/Deprecations.swift; sourceTree = "<group>"; };
8461A2D11E145A08001DA4F8 /* UISideMenuNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UISideMenuNavigationController.swift; path = Pod/Classes/UISideMenuNavigationController.swift; sourceTree = "<group>"; };
8432CC0122FFBCF4003D2BBD /* ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8432CC0322FFBCF5003D2BBD /* ExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleTests.swift; sourceTree = "<group>"; };
8432CC0522FFBCF5003D2BBD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8461A2D11E145A08001DA4F8 /* SideMenuNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SideMenuNavigationController.swift; path = Pod/Classes/SideMenuNavigationController.swift; sourceTree = "<group>"; };
8461A2D21E145A08001DA4F8 /* UITableViewVibrantCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UITableViewVibrantCell.swift; path = Pod/Classes/UITableViewVibrantCell.swift; sourceTree = "<group>"; };
84B489B21DD469B000D6CB43 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
84B489B41DD469B000D6CB43 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
@@ -91,6 +103,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
8432CBFE22FFBCF4003D2BBD /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -118,7 +137,7 @@
842820F022DDD1E800C6F2D8 /* SideMenuPresentationController.swift */,
842820FC22DDD21100C6F2D8 /* SideMenuPresentationStyle.swift */,
842820F222DDD1E800C6F2D8 /* SideMenuTransitionController.swift */,
8461A2D11E145A08001DA4F8 /* UISideMenuNavigationController.swift */,
8461A2D11E145A08001DA4F8 /* SideMenuNavigationController.swift */,
8461A2D21E145A08001DA4F8 /* UITableViewVibrantCell.swift */,
);
name = Source;
@@ -138,22 +157,13 @@
path = Example;
sourceTree = "<group>";
};
7B48A0E91DCB2487002990A1 /* ExampleTests */ = {
isa = PBXGroup;
children = (
7B48A0EA1DCB2487002990A1 /* Tests.swift */,
7B48A0EC1DCB2487002990A1 /* Info.plist */,
);
path = ExampleTests;
sourceTree = "<group>";
};
7B9DC8FA1DC6E8C1000D4007 = {
isa = PBXGroup;
children = (
65FF1B3F1DE33097007B0845 /* Source */,
84B489B81DD469B900D6CB43 /* Podspec Metadata */,
7B48A0D41DCB2487002990A1 /* Example */,
7B48A0E91DCB2487002990A1 /* ExampleTests */,
8432CC0222FFBCF5003D2BBD /* ExampleTests */,
7B9DC9051DC6E8C1000D4007 /* Products */,
9FB98148377EAEC00E35AC14 /* Pods */,
9C94EEEBD250FF394115AAFC /* Frameworks */,
@@ -165,10 +175,20 @@
children = (
7B9DC9041DC6E8C1000D4007 /* SideMenu.framework */,
7B48A0D31DCB2487002990A1 /* Example.app */,
8432CC0122FFBCF4003D2BBD /* ExampleTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
8432CC0222FFBCF5003D2BBD /* ExampleTests */ = {
isa = PBXGroup;
children = (
8432CC0322FFBCF5003D2BBD /* ExampleTests.swift */,
8432CC0522FFBCF5003D2BBD /* Info.plist */,
);
path = ExampleTests;
sourceTree = "<group>";
};
84B489B81DD469B900D6CB43 /* Podspec Metadata */ = {
isa = PBXGroup;
children = (
@@ -253,13 +273,31 @@
productReference = 7B9DC9041DC6E8C1000D4007 /* SideMenu.framework */;
productType = "com.apple.product-type.framework";
};
8432CC0022FFBCF4003D2BBD /* ExampleTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 8432CC0822FFBCF5003D2BBD /* Build configuration list for PBXNativeTarget "ExampleTests" */;
buildPhases = (
8432CBFD22FFBCF4003D2BBD /* Sources */,
8432CBFE22FFBCF4003D2BBD /* Frameworks */,
8432CBFF22FFBCF4003D2BBD /* Resources */,
);
buildRules = (
);
dependencies = (
8432CC0722FFBCF5003D2BBD /* PBXTargetDependency */,
);
name = ExampleTests;
productName = ExampleTests;
productReference = 8432CC0122FFBCF4003D2BBD /* ExampleTests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
7B9DC8FB1DC6E8C1000D4007 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0800;
LastSwiftUpdateCheck = 1030;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = jonkykong;
TargetAttributes = {
@@ -274,6 +312,12 @@
LastSwiftMigration = 0900;
ProvisioningStyle = Automatic;
};
8432CC0022FFBCF4003D2BBD = {
CreatedOnToolsVersion = 10.3;
DevelopmentTeam = QTJ767UH3L;
ProvisioningStyle = Automatic;
TestTargetID = 7B48A0D21DCB2487002990A1;
};
};
};
buildConfigurationList = 7B9DC8FE1DC6E8C1000D4007 /* Build configuration list for PBXProject "SideMenu" */;
@@ -292,6 +336,7 @@
targets = (
7B9DC9031DC6E8C1000D4007 /* SideMenu */,
7B48A0D21DCB2487002990A1 /* Example */,
8432CC0022FFBCF4003D2BBD /* ExampleTests */,
);
};
/* End PBXProject section */
@@ -317,6 +362,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
8432CBFF22FFBCF4003D2BBD /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
@@ -375,7 +427,7 @@
buildActionMask = 2147483647;
files = (
842820EF22DDD1BC00C6F2D8 /* Protected.swift in Sources */,
8461A2D51E145A08001DA4F8 /* UISideMenuNavigationController.swift in Sources */,
8461A2D51E145A08001DA4F8 /* SideMenuNavigationController.swift in Sources */,
842820FD22DDD21100C6F2D8 /* SideMenuPresentationStyle.swift in Sources */,
842820F822DDD1E800C6F2D8 /* SideMenuTransitionController.swift in Sources */,
842820FF22DDD24200C6F2D8 /* SideMenuInteractionController.swift in Sources */,
@@ -390,8 +442,24 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
8432CBFD22FFBCF4003D2BBD /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8432CC0422FFBCF5003D2BBD /* ExampleTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
8432CC0722FFBCF5003D2BBD /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 7B48A0D21DCB2487002990A1 /* Example */;
targetProxy = 8432CC0622FFBCF5003D2BBD /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
7B48A0ED1DCB2487002990A1 /* Debug */ = {
isa = XCBuildConfiguration;
@@ -581,6 +649,53 @@
};
name = Release;
};
8432CC0922FFBCF5003D2BBD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = QTJ767UH3L;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = ExampleTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = co.massappeal.ExampleTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = Example;
};
name = Debug;
};
8432CC0A22FFBCF5003D2BBD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = QTJ767UH3L;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = ExampleTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = co.massappeal.ExampleTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = Example;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -611,6 +726,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
8432CC0822FFBCF5003D2BBD /* Build configuration list for PBXNativeTarget "ExampleTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
8432CC0922FFBCF5003D2BBD /* Debug */,
8432CC0A22FFBCF5003D2BBD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 7B9DC8FB1DC6E8C1000D4007 /* Project object */;
@@ -0,0 +1,101 @@
<?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 = "7B48A0D21DCB2487002990A1"
BuildableName = "Example.app"
BlueprintName = "Example"
ReferencedContainer = "container:SideMenu.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8432CC0022FFBCF4003D2BBD"
BuildableName = "ExampleTests.xctest"
BlueprintName = "ExampleTests"
ReferencedContainer = "container:SideMenu.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7B48A0D21DCB2487002990A1"
BuildableName = "Example.app"
BlueprintName = "Example"
ReferencedContainer = "container:SideMenu.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</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.app"
BlueprintName = "Example"
ReferencedContainer = "container:SideMenu.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7B48A0D21DCB2487002990A1"
BuildableName = "Example.app"
BlueprintName = "Example"
ReferencedContainer = "container:SideMenu.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 135 KiB