From 69c858be668a0053cc6601715941764c5f7b63a0 Mon Sep 17 00:00:00 2001 From: Yilei He Date: Thu, 9 Mar 2017 21:25:51 +1100 Subject: [PATCH] =?UTF-8?q?-=20Add=20Swift=20version.=20The=20Swift=20vers?= =?UTF-8?q?ion=20is=20just=20a=20translation=20of=20the=20original=20objc?= =?UTF-8?q?=20class=20extension.=20It=20doesn=E2=80=99t=20add=20any=20feat?= =?UTF-8?q?ure=20or=20cut=20any=20feature.=20-=20The=20exposed=20functions?= =?UTF-8?q?=20are=20put=20under=20the=20namespace=20fd.=20For=20example:?= =?UTF-8?q?=20viewController.fd.prefersNavigationBarHidden?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FDFullscreenPop.xcodeproj/project.pbxproj | 319 +++++++++++++++ .../contents.xcworkspacedata | 7 + .../FDFullscreenPop/AppDelegate.swift | 46 +++ .../AppIcon.appiconset/Contents.json | 68 ++++ .../Base.lproj/LaunchScreen.storyboard | 27 ++ .../Base.lproj/Main.storyboard | 84 ++++ .../FDFullscreenPop/Info.plist | 45 +++ .../FDFullscreenPop/Random.swift | 38 ++ ...iewController+FDFullscreenPopGesture.swift | 366 ++++++++++++++++++ .../FDFullscreenPop/ViewController.swift | 50 +++ ...iewController+FDFullscreenPopGesture.swift | 366 ++++++++++++++++++ 11 files changed, 1416 insertions(+) create mode 100644 Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop.xcodeproj/project.pbxproj create mode 100644 Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/AppDelegate.swift create mode 100644 Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Base.lproj/LaunchScreen.storyboard create mode 100644 Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Base.lproj/Main.storyboard create mode 100644 Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Info.plist create mode 100644 Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Random.swift create mode 100644 Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/UIViewController+FDFullscreenPopGesture.swift create mode 100644 Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/ViewController.swift create mode 100644 Swift/Source/UIViewController+FDFullscreenPopGesture.swift diff --git a/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop.xcodeproj/project.pbxproj b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop.xcodeproj/project.pbxproj new file mode 100644 index 0000000..0a04951 --- /dev/null +++ b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop.xcodeproj/project.pbxproj @@ -0,0 +1,319 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + B72EA6631E71259700D3E7E4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B72EA6621E71259700D3E7E4 /* AppDelegate.swift */; }; + B72EA6651E71259700D3E7E4 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B72EA6641E71259700D3E7E4 /* ViewController.swift */; }; + B72EA6681E71259700D3E7E4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B72EA6661E71259700D3E7E4 /* Main.storyboard */; }; + B72EA66A1E71259700D3E7E4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B72EA6691E71259700D3E7E4 /* Assets.xcassets */; }; + B72EA66D1E71259700D3E7E4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B72EA66B1E71259700D3E7E4 /* LaunchScreen.storyboard */; }; + B72EA6751E71266E00D3E7E4 /* UIViewController+FDFullscreenPopGesture.swift in Sources */ = {isa = PBXBuildFile; fileRef = B72EA6741E71266E00D3E7E4 /* UIViewController+FDFullscreenPopGesture.swift */; }; + B72EA6771E71267500D3E7E4 /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = B72EA6761E71267500D3E7E4 /* Random.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + B72EA65F1E71259700D3E7E4 /* FDFullscreenPop.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FDFullscreenPop.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B72EA6621E71259700D3E7E4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + B72EA6641E71259700D3E7E4 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + B72EA6671E71259700D3E7E4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + B72EA6691E71259700D3E7E4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B72EA66C1E71259700D3E7E4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + B72EA66E1E71259700D3E7E4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B72EA6741E71266E00D3E7E4 /* UIViewController+FDFullscreenPopGesture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+FDFullscreenPopGesture.swift"; sourceTree = ""; }; + B72EA6761E71267500D3E7E4 /* Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Random.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B72EA65C1E71259700D3E7E4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B72EA6561E71259700D3E7E4 = { + isa = PBXGroup; + children = ( + B72EA6611E71259700D3E7E4 /* FDFullscreenPop */, + B72EA6601E71259700D3E7E4 /* Products */, + ); + sourceTree = ""; + }; + B72EA6601E71259700D3E7E4 /* Products */ = { + isa = PBXGroup; + children = ( + B72EA65F1E71259700D3E7E4 /* FDFullscreenPop.app */, + ); + name = Products; + sourceTree = ""; + }; + B72EA6611E71259700D3E7E4 /* FDFullscreenPop */ = { + isa = PBXGroup; + children = ( + B72EA6621E71259700D3E7E4 /* AppDelegate.swift */, + B72EA6641E71259700D3E7E4 /* ViewController.swift */, + B72EA6661E71259700D3E7E4 /* Main.storyboard */, + B72EA6691E71259700D3E7E4 /* Assets.xcassets */, + B72EA66B1E71259700D3E7E4 /* LaunchScreen.storyboard */, + B72EA66E1E71259700D3E7E4 /* Info.plist */, + B72EA6741E71266E00D3E7E4 /* UIViewController+FDFullscreenPopGesture.swift */, + B72EA6761E71267500D3E7E4 /* Random.swift */, + ); + path = FDFullscreenPop; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B72EA65E1E71259700D3E7E4 /* FDFullscreenPop */ = { + isa = PBXNativeTarget; + buildConfigurationList = B72EA6711E71259700D3E7E4 /* Build configuration list for PBXNativeTarget "FDFullscreenPop" */; + buildPhases = ( + B72EA65B1E71259700D3E7E4 /* Sources */, + B72EA65C1E71259700D3E7E4 /* Frameworks */, + B72EA65D1E71259700D3E7E4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = FDFullscreenPop; + productName = FDFullscreenPop; + productReference = B72EA65F1E71259700D3E7E4 /* FDFullscreenPop.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B72EA6571E71259700D3E7E4 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0820; + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = lionhylra; + TargetAttributes = { + B72EA65E1E71259700D3E7E4 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = 7K48CFLDT2; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = B72EA65A1E71259700D3E7E4 /* Build configuration list for PBXProject "FDFullscreenPop" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B72EA6561E71259700D3E7E4; + productRefGroup = B72EA6601E71259700D3E7E4 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B72EA65E1E71259700D3E7E4 /* FDFullscreenPop */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B72EA65D1E71259700D3E7E4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B72EA66D1E71259700D3E7E4 /* LaunchScreen.storyboard in Resources */, + B72EA66A1E71259700D3E7E4 /* Assets.xcassets in Resources */, + B72EA6681E71259700D3E7E4 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B72EA65B1E71259700D3E7E4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B72EA6751E71266E00D3E7E4 /* UIViewController+FDFullscreenPopGesture.swift in Sources */, + B72EA6771E71267500D3E7E4 /* Random.swift in Sources */, + B72EA6651E71259700D3E7E4 /* ViewController.swift in Sources */, + B72EA6631E71259700D3E7E4 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + B72EA6661E71259700D3E7E4 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B72EA6671E71259700D3E7E4 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + B72EA66B1E71259700D3E7E4 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B72EA66C1E71259700D3E7E4 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + B72EA66F1E71259700D3E7E4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + B72EA6701E71259700D3E7E4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + B72EA6721E71259700D3E7E4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 7K48CFLDT2; + INFOPLIST_FILE = FDFullscreenPop/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.lionhylra.FDFullscreenPop; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + B72EA6731E71259700D3E7E4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 7K48CFLDT2; + INFOPLIST_FILE = FDFullscreenPop/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.lionhylra.FDFullscreenPop; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B72EA65A1E71259700D3E7E4 /* Build configuration list for PBXProject "FDFullscreenPop" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B72EA66F1E71259700D3E7E4 /* Debug */, + B72EA6701E71259700D3E7E4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B72EA6711E71259700D3E7E4 /* Build configuration list for PBXNativeTarget "FDFullscreenPop" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B72EA6721E71259700D3E7E4 /* Debug */, + B72EA6731E71259700D3E7E4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = B72EA6571E71259700D3E7E4 /* Project object */; +} diff --git a/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..7da5144 --- /dev/null +++ b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/AppDelegate.swift b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/AppDelegate.swift new file mode 100644 index 0000000..c89a04f --- /dev/null +++ b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// FDFullscreenPop +// +// Created by Yilei on 9/3/17. +// Copyright © 2017 lionhylra. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Assets.xcassets/AppIcon.appiconset/Contents.json b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..36d2c80 --- /dev/null +++ b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Base.lproj/LaunchScreen.storyboard b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Base.lproj/Main.storyboard b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Base.lproj/Main.storyboard new file mode 100644 index 0000000..480eb68 --- /dev/null +++ b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Base.lproj/Main.storyboard @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Info.plist b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Info.plist new file mode 100644 index 0000000..d052473 --- /dev/null +++ b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Random.swift b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Random.swift new file mode 100644 index 0000000..1429e06 --- /dev/null +++ b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/Random.swift @@ -0,0 +1,38 @@ +// +// Algorithm.swift +// +// +// Created by Yilei He on 14/04/2016. +// Copyright © 2016 lionhylra.com. All rights reserved. +// + +import UIKit + +// MARK: - Random number - +extension UInt32 { + static var random: UInt32 { + return arc4random() + } + + + static func random(range: Range) -> UInt32 { + return arc4random_uniform(range.upperBound - range.lowerBound) + range.lowerBound + } +} + + + +extension Int { + static var random: Int { + return Int(UInt32.random) + } + + + + static func random(range: Range) -> Int { + return Int(UInt32.random(range: range)) + } +} + + + diff --git a/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/UIViewController+FDFullscreenPopGesture.swift b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/UIViewController+FDFullscreenPopGesture.swift new file mode 100644 index 0000000..ea469cf --- /dev/null +++ b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/UIViewController+FDFullscreenPopGesture.swift @@ -0,0 +1,366 @@ +// +// UIViewController+ FDFullscreenPopGesture.swift +// Swift3Project +// +// Created by Yilei on 27/2/17. +// Copyright © 2017 lionhylra.com. All rights reserved. +// + +import UIKit +import ObjectiveC + +public protocol FDProxyConvertible {} + +extension FDProxyConvertible { + public var fd: FDProxy { + return FDProxy(base: self) + } +} + +extension UIViewController: FDProxyConvertible {} + +public class FDProxy { + fileprivate let base: T + fileprivate init(base: T) { + self.base = base + } +} + +// MARK: - Associated Object(private) - + +private var _fullscreenPopGestureRecognizerAssociationKey: UInt8 = 0 +private var _viewControllerBasedNavigationBarAppearanceEnabledAssociationKey: UInt8 = 0 + +extension UINavigationController { + + + + fileprivate var _fullscreenPopGestureRecognizer: UIPanGestureRecognizer! { + if let panGestureRecognizer = objc_getAssociatedObject(self, &_fullscreenPopGestureRecognizerAssociationKey) as? UIPanGestureRecognizer { + return panGestureRecognizer + } + let pan = UIPanGestureRecognizer() + pan.maximumNumberOfTouches = 1 + objc_setAssociatedObject(self, &_fullscreenPopGestureRecognizerAssociationKey, pan, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + return pan + + } + + + + fileprivate var _viewControllerBasedNavigationBarAppearanceEnabled: Bool { + get { + return objc_getAssociatedObject(self, &_viewControllerBasedNavigationBarAppearanceEnabledAssociationKey) as? Bool ?? true + } + set { + objc_setAssociatedObject(self, &_viewControllerBasedNavigationBarAppearanceEnabledAssociationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } +} + + +private var _interactivePopDisabledAssociationKey: UInt8 = 0 +private var _prefersNavigationBarHiddenAssociationKey: UInt8 = 0 +private var _interactivePopMaxAllowedInitialDistanceToLeftEdgeAssociationKey: UInt8 = 0 + +extension UIViewController { + + + + fileprivate var _interactivePopDisabled: Bool { + get { + return objc_getAssociatedObject(self, &_interactivePopDisabledAssociationKey) as? Bool ?? false + } + set { + return objc_setAssociatedObject(self, &_interactivePopDisabledAssociationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + + + + fileprivate var _prefersNavigationBarHidden: Bool { + get { + return objc_getAssociatedObject(self, &_prefersNavigationBarHiddenAssociationKey) as? Bool ?? false + } + set { + objc_setAssociatedObject(self, &_prefersNavigationBarHiddenAssociationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + + + + fileprivate var _interactivePopMaxAllowedInitialDistanceToLeftEdge: CGFloat { + get { + return objc_getAssociatedObject(self, &_interactivePopMaxAllowedInitialDistanceToLeftEdgeAssociationKey) as? CGFloat ?? 0 + } + set { + objc_setAssociatedObject(self, &_interactivePopMaxAllowedInitialDistanceToLeftEdgeAssociationKey, max(newValue, 0), .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } +} + +// MARK: - Public properties - + +extension FDProxy where T: UINavigationController { + + /// The gesture recognizer that actually handles interactive pop. + public var fullscreenPopGestureRecognizer: UIPanGestureRecognizer! { + get { + return base._fullscreenPopGestureRecognizer + } + //set{ + // base._fullscreenPopGestureRecognizer = newValue + //} + } + + + /// A view controller is able to control navigation bar's appearance by itself, + /// rather than a global way, checking "fd_prefersNavigationBarHidden" property. + /// Default to YES, disable it if you don't want so. + public var viewControllerBasedNavigationBarAppearanceEnabled: Bool { + get { + return base._viewControllerBasedNavigationBarAppearanceEnabled + } + set { + base._viewControllerBasedNavigationBarAppearanceEnabled = newValue + } + } +} + + + +extension FDProxy where T: UIViewController { + + public var interactivePopDisabled: Bool { + get { + return base._interactivePopDisabled + } + set { + base._interactivePopDisabled = newValue + } + } + + + public var prefersNavigationBarHidden: Bool { + get { + return base._prefersNavigationBarHidden + } + set { + base._prefersNavigationBarHidden = newValue + } + } + + + public var interactivePopMaxAllowedInitialDistanceToLeftEdge: CGFloat { + get { + return base._interactivePopMaxAllowedInitialDistanceToLeftEdge + } + set { + base._interactivePopMaxAllowedInitialDistanceToLeftEdge = newValue + } + } +} + + + +// MARK: - Private Implementation - + +fileprivate class _FDFullscreenPopGestureRecognizerDelegate: NSObject, UIGestureRecognizerDelegate { + weak var navigationController: UINavigationController! + + func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + + if navigationController.viewControllers.count <= 1 { + return false + } + + if let topViewController = navigationController.topViewController { + if topViewController.fd.interactivePopDisabled { + return false + } + + let beginningLocation = gestureRecognizer.location(in: gestureRecognizer.view) + let maxAllowed = topViewController.fd.interactivePopMaxAllowedInitialDistanceToLeftEdge + if maxAllowed > 0 && beginningLocation.x > maxAllowed { + return false + } + } + + if let isTransitioning = navigationController.value(forKey: "_isTransitioning") as? Bool, isTransitioning { + return false + } + + if let pan = gestureRecognizer as? UIPanGestureRecognizer { + let translation = pan.translation(in: gestureRecognizer.view) + if translation.x <= 0 { + return false + } + } + + + + return true + } +} + + +private class BlockWrapper: NSObject { + let closure: (UIViewController, Bool) -> Void + init(closure: @escaping (UIViewController, Bool) -> Void) { + self.closure = closure + } +} + +private var _fdViewWillAppearInjectBlockAssociationKey: UInt8 = 0 +extension UIViewController { + fileprivate typealias FDViewWillAppearInjectBlock = (UIViewController, Bool) -> Void + fileprivate var _fdViewWillAppearInjectBlock: BlockWrapper? { + get { + return objc_getAssociatedObject(self, &_fdViewWillAppearInjectBlockAssociationKey) as? BlockWrapper + } + set { + objc_setAssociatedObject(self, &_fdViewWillAppearInjectBlockAssociationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + +} + +// MARK: - METHOD SWIZZLING - + +/* Configuration */ +private let MethodMapping1:Dictionary = [ + "viewWillAppear:":"swizzled_viewWillAppear:" +] + + +private let swizzlingClass1 = UIViewController.self + +extension UIViewController { + + override open class func initialize() { + + /* Filter classes */ + guard self === swizzlingClass1 else { return } + swizzling1 + } + + + func swizzled_viewWillAppear(_ animated: Bool) { + self.swizzled_viewWillAppear(animated) + self._fdViewWillAppearInjectBlock?.closure(self, animated) + } +} + + +private let swizzling1: () = { + for (originalSelector,swizzledSelector) in MethodMapping1 { + let originalSelector = Selector(originalSelector) + let swizzledSelector = Selector(swizzledSelector) + + let originalMethod = class_getInstanceMethod(swizzlingClass1, originalSelector) + let swizzledMethod = class_getInstanceMethod(swizzlingClass1, swizzledSelector) + + let didAddMethod = class_addMethod(swizzlingClass1, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) + + if didAddMethod { + class_replaceMethod(swizzlingClass1, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) + } else { + method_exchangeImplementations(originalMethod, swizzledMethod) + } + } +}() + + +/* Configuration */ +private let MethodMapping2:Dictionary = [ + "pushViewController:animated:":"swizzled_pushViewController:animated:" +] + + +private let swizzlingClass2 = UINavigationController.self + +extension UINavigationController { + + override open class func initialize() { + + /* Filter classes */ + guard self === swizzlingClass2 else { return } + swizzling2 + } + + + + func swizzled_pushViewController(_ viewController: UIViewController, animated: Bool) { + if interactivePopGestureRecognizer?.view?.gestureRecognizers?.contains(self.fd.fullscreenPopGestureRecognizer) == false { + + self.interactivePopGestureRecognizer?.view?.addGestureRecognizer(self.fd.fullscreenPopGestureRecognizer) + + let internalTargets = interactivePopGestureRecognizer?.value(forKey: "targets") as? [AnyObject] + let internalTarget = internalTargets?.first?.value(forKey: "target") + let internalAction = Selector(("handleNavigationTransition:")) + fd.fullscreenPopGestureRecognizer.delegate = _fdPopGestureRecognizerDelegate + fd.fullscreenPopGestureRecognizer.addTarget(internalTarget as Any, action: internalAction) + + self.interactivePopGestureRecognizer?.isEnabled = false + + } + + fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded(appearingViewController: viewController) + + if !viewControllers.contains(viewController) { + swizzled_pushViewController(viewController, animated: animated) + } + } + + + private func fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded(appearingViewController: UIViewController) { + if !fd.viewControllerBasedNavigationBarAppearanceEnabled { + return + } + + let block: FDViewWillAppearInjectBlock = { [weak self] (viewController: UIViewController, animated: Bool) -> Void in + self?.setNavigationBarHidden(viewController.fd.prefersNavigationBarHidden, animated: animated) + } + + appearingViewController._fdViewWillAppearInjectBlock = BlockWrapper(closure: block) + if let disappearingViewController = viewControllers.last, disappearingViewController._fdViewWillAppearInjectBlock == nil { + disappearingViewController._fdViewWillAppearInjectBlock = BlockWrapper(closure: block) + } + + } +} + + +private let swizzling2: () = { + for (originalSelector,swizzledSelector) in MethodMapping2 { + let originalSelector = Selector(originalSelector) + let swizzledSelector = Selector(swizzledSelector) + + let originalMethod = class_getInstanceMethod(swizzlingClass2, originalSelector) + let swizzledMethod = class_getInstanceMethod(swizzlingClass2, swizzledSelector) + + let didAddMethod = class_addMethod(swizzlingClass2, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) + + if didAddMethod { + class_replaceMethod(swizzlingClass2, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) + } else { + method_exchangeImplementations(originalMethod, swizzledMethod) + } + } +}() + + +private var _fdPopGestureRecognizerDelegateAssociationKey: UInt8 = 0 +extension UINavigationController { + fileprivate var _fdPopGestureRecognizerDelegate: _FDFullscreenPopGestureRecognizerDelegate { + if let delegate = objc_getAssociatedObject(self, &_fdPopGestureRecognizerDelegateAssociationKey) as? _FDFullscreenPopGestureRecognizerDelegate { + return delegate + } + + let delegate = _FDFullscreenPopGestureRecognizerDelegate() + delegate.navigationController = self + objc_setAssociatedObject(self, &_fdPopGestureRecognizerDelegateAssociationKey, delegate, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + + return delegate + } +} diff --git a/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/ViewController.swift b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/ViewController.swift new file mode 100644 index 0000000..1ce8bcf --- /dev/null +++ b/Swift/FDFullscreenPopGestureDemo-Swift/FDFullscreenPop/ViewController.swift @@ -0,0 +1,50 @@ +// +// ViewController.swift +// FDFullscreenPop +// +// Created by Yilei on 9/3/17. +// Copyright © 2017 lionhylra. All rights reserved. +// + +import UIKit + +var i = 0 + +class ViewController: UIViewController { + + @IBOutlet weak var label: UILabel! + + + override func viewDidLoad() { + super.viewDidLoad() + + + label.text = "\(i)" + defer {i += 1} + + fd.interactivePopMaxAllowedInitialDistanceToLeftEdge = 20 + + let n = Int.random(range: 0..<2) + if n == 0 { + fd.prefersNavigationBarHidden = true + label.text! += " no nav" +// fd.interactivePopDisabled = true + } else { + fd.prefersNavigationBarHidden = false + } + + self.title = label.text + } + + + @IBAction func prev(_ sender: UIButton) { + _ = navigationController?.popViewController(animated: true) + } + + @IBAction func next(_ sender: UIButton) { + let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "VC") + navigationController?.pushViewController(vc, animated: true) + + } +} + diff --git a/Swift/Source/UIViewController+FDFullscreenPopGesture.swift b/Swift/Source/UIViewController+FDFullscreenPopGesture.swift new file mode 100644 index 0000000..ea469cf --- /dev/null +++ b/Swift/Source/UIViewController+FDFullscreenPopGesture.swift @@ -0,0 +1,366 @@ +// +// UIViewController+ FDFullscreenPopGesture.swift +// Swift3Project +// +// Created by Yilei on 27/2/17. +// Copyright © 2017 lionhylra.com. All rights reserved. +// + +import UIKit +import ObjectiveC + +public protocol FDProxyConvertible {} + +extension FDProxyConvertible { + public var fd: FDProxy { + return FDProxy(base: self) + } +} + +extension UIViewController: FDProxyConvertible {} + +public class FDProxy { + fileprivate let base: T + fileprivate init(base: T) { + self.base = base + } +} + +// MARK: - Associated Object(private) - + +private var _fullscreenPopGestureRecognizerAssociationKey: UInt8 = 0 +private var _viewControllerBasedNavigationBarAppearanceEnabledAssociationKey: UInt8 = 0 + +extension UINavigationController { + + + + fileprivate var _fullscreenPopGestureRecognizer: UIPanGestureRecognizer! { + if let panGestureRecognizer = objc_getAssociatedObject(self, &_fullscreenPopGestureRecognizerAssociationKey) as? UIPanGestureRecognizer { + return panGestureRecognizer + } + let pan = UIPanGestureRecognizer() + pan.maximumNumberOfTouches = 1 + objc_setAssociatedObject(self, &_fullscreenPopGestureRecognizerAssociationKey, pan, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + return pan + + } + + + + fileprivate var _viewControllerBasedNavigationBarAppearanceEnabled: Bool { + get { + return objc_getAssociatedObject(self, &_viewControllerBasedNavigationBarAppearanceEnabledAssociationKey) as? Bool ?? true + } + set { + objc_setAssociatedObject(self, &_viewControllerBasedNavigationBarAppearanceEnabledAssociationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } +} + + +private var _interactivePopDisabledAssociationKey: UInt8 = 0 +private var _prefersNavigationBarHiddenAssociationKey: UInt8 = 0 +private var _interactivePopMaxAllowedInitialDistanceToLeftEdgeAssociationKey: UInt8 = 0 + +extension UIViewController { + + + + fileprivate var _interactivePopDisabled: Bool { + get { + return objc_getAssociatedObject(self, &_interactivePopDisabledAssociationKey) as? Bool ?? false + } + set { + return objc_setAssociatedObject(self, &_interactivePopDisabledAssociationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + + + + fileprivate var _prefersNavigationBarHidden: Bool { + get { + return objc_getAssociatedObject(self, &_prefersNavigationBarHiddenAssociationKey) as? Bool ?? false + } + set { + objc_setAssociatedObject(self, &_prefersNavigationBarHiddenAssociationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + + + + fileprivate var _interactivePopMaxAllowedInitialDistanceToLeftEdge: CGFloat { + get { + return objc_getAssociatedObject(self, &_interactivePopMaxAllowedInitialDistanceToLeftEdgeAssociationKey) as? CGFloat ?? 0 + } + set { + objc_setAssociatedObject(self, &_interactivePopMaxAllowedInitialDistanceToLeftEdgeAssociationKey, max(newValue, 0), .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } +} + +// MARK: - Public properties - + +extension FDProxy where T: UINavigationController { + + /// The gesture recognizer that actually handles interactive pop. + public var fullscreenPopGestureRecognizer: UIPanGestureRecognizer! { + get { + return base._fullscreenPopGestureRecognizer + } + //set{ + // base._fullscreenPopGestureRecognizer = newValue + //} + } + + + /// A view controller is able to control navigation bar's appearance by itself, + /// rather than a global way, checking "fd_prefersNavigationBarHidden" property. + /// Default to YES, disable it if you don't want so. + public var viewControllerBasedNavigationBarAppearanceEnabled: Bool { + get { + return base._viewControllerBasedNavigationBarAppearanceEnabled + } + set { + base._viewControllerBasedNavigationBarAppearanceEnabled = newValue + } + } +} + + + +extension FDProxy where T: UIViewController { + + public var interactivePopDisabled: Bool { + get { + return base._interactivePopDisabled + } + set { + base._interactivePopDisabled = newValue + } + } + + + public var prefersNavigationBarHidden: Bool { + get { + return base._prefersNavigationBarHidden + } + set { + base._prefersNavigationBarHidden = newValue + } + } + + + public var interactivePopMaxAllowedInitialDistanceToLeftEdge: CGFloat { + get { + return base._interactivePopMaxAllowedInitialDistanceToLeftEdge + } + set { + base._interactivePopMaxAllowedInitialDistanceToLeftEdge = newValue + } + } +} + + + +// MARK: - Private Implementation - + +fileprivate class _FDFullscreenPopGestureRecognizerDelegate: NSObject, UIGestureRecognizerDelegate { + weak var navigationController: UINavigationController! + + func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + + if navigationController.viewControllers.count <= 1 { + return false + } + + if let topViewController = navigationController.topViewController { + if topViewController.fd.interactivePopDisabled { + return false + } + + let beginningLocation = gestureRecognizer.location(in: gestureRecognizer.view) + let maxAllowed = topViewController.fd.interactivePopMaxAllowedInitialDistanceToLeftEdge + if maxAllowed > 0 && beginningLocation.x > maxAllowed { + return false + } + } + + if let isTransitioning = navigationController.value(forKey: "_isTransitioning") as? Bool, isTransitioning { + return false + } + + if let pan = gestureRecognizer as? UIPanGestureRecognizer { + let translation = pan.translation(in: gestureRecognizer.view) + if translation.x <= 0 { + return false + } + } + + + + return true + } +} + + +private class BlockWrapper: NSObject { + let closure: (UIViewController, Bool) -> Void + init(closure: @escaping (UIViewController, Bool) -> Void) { + self.closure = closure + } +} + +private var _fdViewWillAppearInjectBlockAssociationKey: UInt8 = 0 +extension UIViewController { + fileprivate typealias FDViewWillAppearInjectBlock = (UIViewController, Bool) -> Void + fileprivate var _fdViewWillAppearInjectBlock: BlockWrapper? { + get { + return objc_getAssociatedObject(self, &_fdViewWillAppearInjectBlockAssociationKey) as? BlockWrapper + } + set { + objc_setAssociatedObject(self, &_fdViewWillAppearInjectBlockAssociationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + +} + +// MARK: - METHOD SWIZZLING - + +/* Configuration */ +private let MethodMapping1:Dictionary = [ + "viewWillAppear:":"swizzled_viewWillAppear:" +] + + +private let swizzlingClass1 = UIViewController.self + +extension UIViewController { + + override open class func initialize() { + + /* Filter classes */ + guard self === swizzlingClass1 else { return } + swizzling1 + } + + + func swizzled_viewWillAppear(_ animated: Bool) { + self.swizzled_viewWillAppear(animated) + self._fdViewWillAppearInjectBlock?.closure(self, animated) + } +} + + +private let swizzling1: () = { + for (originalSelector,swizzledSelector) in MethodMapping1 { + let originalSelector = Selector(originalSelector) + let swizzledSelector = Selector(swizzledSelector) + + let originalMethod = class_getInstanceMethod(swizzlingClass1, originalSelector) + let swizzledMethod = class_getInstanceMethod(swizzlingClass1, swizzledSelector) + + let didAddMethod = class_addMethod(swizzlingClass1, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) + + if didAddMethod { + class_replaceMethod(swizzlingClass1, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) + } else { + method_exchangeImplementations(originalMethod, swizzledMethod) + } + } +}() + + +/* Configuration */ +private let MethodMapping2:Dictionary = [ + "pushViewController:animated:":"swizzled_pushViewController:animated:" +] + + +private let swizzlingClass2 = UINavigationController.self + +extension UINavigationController { + + override open class func initialize() { + + /* Filter classes */ + guard self === swizzlingClass2 else { return } + swizzling2 + } + + + + func swizzled_pushViewController(_ viewController: UIViewController, animated: Bool) { + if interactivePopGestureRecognizer?.view?.gestureRecognizers?.contains(self.fd.fullscreenPopGestureRecognizer) == false { + + self.interactivePopGestureRecognizer?.view?.addGestureRecognizer(self.fd.fullscreenPopGestureRecognizer) + + let internalTargets = interactivePopGestureRecognizer?.value(forKey: "targets") as? [AnyObject] + let internalTarget = internalTargets?.first?.value(forKey: "target") + let internalAction = Selector(("handleNavigationTransition:")) + fd.fullscreenPopGestureRecognizer.delegate = _fdPopGestureRecognizerDelegate + fd.fullscreenPopGestureRecognizer.addTarget(internalTarget as Any, action: internalAction) + + self.interactivePopGestureRecognizer?.isEnabled = false + + } + + fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded(appearingViewController: viewController) + + if !viewControllers.contains(viewController) { + swizzled_pushViewController(viewController, animated: animated) + } + } + + + private func fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded(appearingViewController: UIViewController) { + if !fd.viewControllerBasedNavigationBarAppearanceEnabled { + return + } + + let block: FDViewWillAppearInjectBlock = { [weak self] (viewController: UIViewController, animated: Bool) -> Void in + self?.setNavigationBarHidden(viewController.fd.prefersNavigationBarHidden, animated: animated) + } + + appearingViewController._fdViewWillAppearInjectBlock = BlockWrapper(closure: block) + if let disappearingViewController = viewControllers.last, disappearingViewController._fdViewWillAppearInjectBlock == nil { + disappearingViewController._fdViewWillAppearInjectBlock = BlockWrapper(closure: block) + } + + } +} + + +private let swizzling2: () = { + for (originalSelector,swizzledSelector) in MethodMapping2 { + let originalSelector = Selector(originalSelector) + let swizzledSelector = Selector(swizzledSelector) + + let originalMethod = class_getInstanceMethod(swizzlingClass2, originalSelector) + let swizzledMethod = class_getInstanceMethod(swizzlingClass2, swizzledSelector) + + let didAddMethod = class_addMethod(swizzlingClass2, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) + + if didAddMethod { + class_replaceMethod(swizzlingClass2, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) + } else { + method_exchangeImplementations(originalMethod, swizzledMethod) + } + } +}() + + +private var _fdPopGestureRecognizerDelegateAssociationKey: UInt8 = 0 +extension UINavigationController { + fileprivate var _fdPopGestureRecognizerDelegate: _FDFullscreenPopGestureRecognizerDelegate { + if let delegate = objc_getAssociatedObject(self, &_fdPopGestureRecognizerDelegateAssociationKey) as? _FDFullscreenPopGestureRecognizerDelegate { + return delegate + } + + let delegate = _FDFullscreenPopGestureRecognizerDelegate() + delegate.navigationController = self + objc_setAssociatedObject(self, &_fdPopGestureRecognizerDelegateAssociationKey, delegate, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + + return delegate + } +}