├── Snapshots
└── 1.gif
├── XLPopGestureDemo
├── XLPopGestureDemo
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── tabbar.imageset
│ │ │ ├── tabbar@2x.png
│ │ │ ├── tabbar@3x.png
│ │ │ └── Contents.json
│ │ ├── tabbar_selected.imageset
│ │ │ ├── tabbar_selected@2x.png
│ │ │ ├── tabbar_selected@3x.png
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── XLOneViewController.h
│ ├── AppDelegate.h
│ ├── main.m
│ ├── Info.plist
│ ├── XLOneViewController.m
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ └── AppDelegate.m
└── XLPopGestureDemo.xcodeproj
│ ├── project.xcworkspace
│ └── contents.xcworkspacedata
│ └── project.pbxproj
├── XLPopGesture.podspec
├── LICENSE
├── README.md
├── .gitignore
└── XLPopGesture
├── UINavigationController+XLPopGesture.h
└── UINavigationController+XLPopGesture.m
/Snapshots/1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cctomato/XLPopGesture/HEAD/Snapshots/1.gif
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/Assets.xcassets/tabbar.imageset/tabbar@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cctomato/XLPopGesture/HEAD/XLPopGestureDemo/XLPopGestureDemo/Assets.xcassets/tabbar.imageset/tabbar@2x.png
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/Assets.xcassets/tabbar.imageset/tabbar@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cctomato/XLPopGesture/HEAD/XLPopGestureDemo/XLPopGestureDemo/Assets.xcassets/tabbar.imageset/tabbar@3x.png
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/Assets.xcassets/tabbar_selected.imageset/tabbar_selected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cctomato/XLPopGesture/HEAD/XLPopGestureDemo/XLPopGestureDemo/Assets.xcassets/tabbar_selected.imageset/tabbar_selected@2x.png
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/Assets.xcassets/tabbar_selected.imageset/tabbar_selected@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cctomato/XLPopGesture/HEAD/XLPopGestureDemo/XLPopGestureDemo/Assets.xcassets/tabbar_selected.imageset/tabbar_selected@3x.png
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/XLOneViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // XLOneViewController.h
3 | // XLPopGestureDemo
4 | //
5 | // Created by cai cai on 2017/3/30.
6 | // Copyright © 2017年 cai cai. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface XLOneViewController : UIViewController
12 | @property (nonatomic, assign) NSInteger index;
13 | @end
14 |
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // XLPopGestureDemo
4 | //
5 | // Created by cai cai on 2017/3/30.
6 | // Copyright © 2017年 cai cai. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // XLPopGestureDemo
4 | //
5 | // Created by cai cai on 2017/3/30.
6 | // Copyright © 2017年 cai cai. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/Assets.xcassets/tabbar.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "tabbar@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "tabbar@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/Assets.xcassets/tabbar_selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "tabbar_selected@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "tabbar_selected@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/XLPopGesture.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "XLPopGesture"
3 | s.version = "2.0"
4 | s.summary = "A custom PopGesture with AOP."
5 | s.description = "A custom PopGesture with AOP. Just pod in 2 files and no need for any setups."
6 | s.homepage = "https://github.com/cctomato/XLPopGesture"
7 |
8 | s.license = { :type => "MIT", :file => "LICENSE" }
9 |
10 | s.author = { "cctomato" => "cyq_1103@live.com" }
11 |
12 | s.platform = :ios, "7.0"
13 |
14 | s.source = { :git => "https://github.com/cctomato/XLPopGesture.git", :tag => "#{s.version}" }
15 |
16 | s.source_files = "XLPopGesture/*.{h,m}"
17 |
18 | s.requires_arc = true
19 |
20 | end
21 |
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | }
43 | ],
44 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 cctomato
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # XLPopGesture
2 | An UINavigationController's category to enable fullscreen pop gesture in an iOS7+ system style with AOP.
3 |
4 | # Overview
5 |
6 | 
7 |
8 | Design ideas come from [FDFullscreenPopGesture](https://github.com/forkingdog/FDFullscreenPopGesture) and [MVVMReactiveCocoa](https://github.com/leichunfeng/MVVMReactiveCocoa)
9 |
10 | Thanks for sharing.
11 |
12 | # Usage
13 |
14 | AOP, just add 2 files and no need for any setups, all navigation controllers will be able to use fullscreen pop gesture automatically.
15 |
16 | To disable this pop gesture of a view controller:
17 |
18 | ```objc
19 | viewController.xl_prefersDisablePop = YES;
20 | ```
21 |
22 | To hidden the navigationBar of a view controller:
23 |
24 | ```objc
25 | viewController.xl_prefersNavigationBarHidden = YES;
26 | ```
27 |
28 | To close the Pop effects of a navigationController:
29 |
30 | ```objc
31 | navigationController.xl_prefersOpenPopEffects = NO;
32 | ```
33 |
34 | TabbarItem will be hidden when push ViewController,if you do not want this:
35 |
36 | ```objc
37 | navigationController.xl_prefersHiddenTabBar = NO;
38 | ```
39 |
40 | # Installation
41 |
42 | Use CocoaPods
43 |
44 | ```ruby
45 | pod 'XLPopGesture'
46 | ```
47 |
48 | #License
49 |
50 | MIT
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIRequiredDeviceCapabilities
26 |
27 | armv7
28 |
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/XLOneViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // XLOneViewController.m
3 | // XLPopGestureDemo
4 | //
5 | // Created by cai cai on 2017/3/30.
6 | // Copyright © 2017年 cai cai. All rights reserved.
7 | //
8 |
9 | #import "XLOneViewController.h"
10 | #import "UINavigationController+XLPopGesture.h"
11 |
12 | @interface XLOneViewController ()
13 |
14 | @end
15 |
16 | @implementation XLOneViewController
17 |
18 | - (void)viewDidLoad {
19 | [super viewDidLoad];
20 | // Do any additional setup after loading the view.
21 | // self.view.backgroundColor = [UIColor whiteColor];
22 | self.view.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1.0];
23 | self.navigationItem.title = [NSString stringWithFormat:@"页面%ld", self.index];
24 |
25 | [self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickTap)]];
26 | }
27 |
28 | - (void)clickTap
29 | {
30 | XLOneViewController *vc = [[XLOneViewController alloc] init];
31 | vc.index = self.index + 1;
32 | [self.navigationController pushViewController:vc animated:YES];
33 | }
34 |
35 | /*
36 | #pragma mark - Navigation
37 |
38 | // In a storyboard-based application, you will often want to do a little preparation before navigation
39 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
40 | // Get the new view controller using [segue destinationViewController].
41 | // Pass the selected object to the new view controller.
42 | }
43 | */
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | .DS_Store
6 |
7 | ## Build generated
8 | build/
9 | DerivedData/
10 |
11 | ## Various settings
12 | *.pbxuser
13 | !default.pbxuser
14 | *.mode1v3
15 | !default.mode1v3
16 | *.mode2v3
17 | !default.mode2v3
18 | *.perspectivev3
19 | !default.perspectivev3
20 | xcuserdata/
21 |
22 | ## Other
23 | *.moved-aside
24 | *.xcuserstate
25 |
26 | ## Obj-C/Swift specific
27 | *.hmap
28 | *.ipa
29 | *.dSYM.zip
30 | *.dSYM
31 |
32 | # CocoaPods
33 | #
34 | # We recommend against adding the Pods directory to your .gitignore. However
35 | # you should judge for yourself, the pros and cons are mentioned at:
36 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
37 | #
38 | Pods/
39 | Podfile.lock
40 |
41 | # Carthage
42 | #
43 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
44 | # Carthage/Checkouts
45 |
46 | Carthage/Build
47 |
48 | # fastlane
49 | #
50 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
51 | # screenshots whenever they are needed.
52 | # For more information about the recommended setup visit:
53 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
54 |
55 | fastlane/report.xml
56 | fastlane/Preview.html
57 | fastlane/screenshots
58 | fastlane/test_output
59 |
60 | # Code Injection
61 | #
62 | # After new code Injection tools there's a generated folder /iOSInjectionProject
63 | # https://github.com/johnno1962/injectionforxcode
64 |
65 | iOSInjectionProject/
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/XLPopGesture/UINavigationController+XLPopGesture.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2016-2017 cctomato ( https://github.com/cctomato )
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | #import
24 |
25 | @interface UIViewController (XLPopGesture)
26 | /**
27 | *A snapshot view based on the contents of the current view
28 | **/
29 | @property (nonatomic, strong) UIView *xl_snapshot;
30 | /**
31 | *Default to NO, if you want to hidden navgationBar, Set YES
32 | **/
33 | @property (nonatomic, assign) BOOL xl_prefersNavigationBarHidden;
34 | /**
35 | *Default to NO, if you want to disable the pop gesture, Set YES
36 | **/
37 | @property (nonatomic, assign) BOOL xl_prefersDisablePop;
38 |
39 | @end
40 |
41 | @interface UINavigationController (XLPopGesture)
42 | /**
43 | *A view controller is able to control navigation bar's appearance by itself,
44 | *rather than a global way, checking "xl_prefersNavigationBarHidden" property.
45 | *Default to YES, disable it if you don't want so.
46 | **/
47 | @property (nonatomic, assign) BOOL xl_viewControllerBasedNavigationBarAppearanceEnabled;
48 | /**
49 | *The gesture recognizer that actually handles interactive pop.
50 | **/
51 | @property (nonatomic, strong, readonly) UIPanGestureRecognizer *xl_popRecoginzer;
52 | /**
53 | *Default to YES, if you do not want to hidden tabBar, set NO
54 | **/
55 | @property (nonatomic, assign) BOOL xl_prefersHiddenTabBar;
56 | /**
57 | *Default to YES, if you do not want to close the Pop effects, set NO
58 | **/
59 | @property (nonatomic, assign) BOOL xl_prefersOpenPopEffects;
60 | /**
61 | *The gesture percentage
62 | **/
63 | @property (nonatomic, strong) UIPercentDrivenInteractiveTransition *xl_interactivePopTransition;
64 | @end
65 |
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // XLPopGestureDemo
4 | //
5 | // Created by cai cai on 2017/3/30.
6 | // Copyright © 2017年 cai cai. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import "XLOneViewController.h"
11 | #import "UINavigationController+XLPopGesture.h"
12 |
13 | @interface AppDelegate ()
14 |
15 | @end
16 |
17 | @implementation AppDelegate
18 |
19 |
20 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
21 | // Override point for customization after application launch.
22 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
23 |
24 | UITabBarController *tabBar = [[UITabBarController alloc] init];
25 |
26 | UINavigationController *nav1 = [[UINavigationController alloc] initWithRootViewController:[[XLOneViewController alloc] init]];
27 | nav1.tabBarItem.title = @"首页1";
28 | nav1.tabBarItem.image = [UIImage imageNamed:@"tabbar_selected"];
29 | nav1.tabBarItem.selectedImage = [[UIImage imageNamed:@"tabbar"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
30 | [tabBar addChildViewController:nav1];
31 |
32 | UINavigationController *nav2 = [[UINavigationController alloc] initWithRootViewController:[[XLOneViewController alloc] init]];
33 | nav2.xl_prefersHiddenTabBar = NO;
34 | nav2.tabBarItem.title = @"首页2";
35 | nav2.tabBarItem.image = [UIImage imageNamed:@"tabbar_selected"];
36 | nav2.tabBarItem.selectedImage = [[UIImage imageNamed:@"tabbar"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
37 | [tabBar addChildViewController:nav2];
38 |
39 | UINavigationController *nav3 = [[UINavigationController alloc] initWithRootViewController:[[XLOneViewController alloc] init]];
40 | nav3.xl_prefersOpenPopEffects = NO;
41 | nav3.tabBarItem.title = @"首页3";
42 | nav3.tabBarItem.image = [UIImage imageNamed:@"tabbar_selected"];
43 | nav3.tabBarItem.selectedImage = [[UIImage imageNamed:@"tabbar"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
44 | [tabBar addChildViewController:nav3];
45 |
46 | UINavigationController *nav4 = [[UINavigationController alloc] initWithRootViewController:[[XLOneViewController alloc] init]];
47 | nav4.xl_prefersHiddenTabBar = NO;
48 | nav4.xl_prefersOpenPopEffects = NO;
49 | nav4.tabBarItem.title = @"首页4";
50 | nav4.tabBarItem.image = [UIImage imageNamed:@"tabbar_selected"];
51 | nav4.tabBarItem.selectedImage = [[UIImage imageNamed:@"tabbar"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
52 | [tabBar addChildViewController:nav4];
53 |
54 | self.window.rootViewController = tabBar;
55 | [self.window makeKeyAndVisible];
56 | return YES;
57 | }
58 |
59 |
60 | - (void)applicationWillResignActive:(UIApplication *)application {
61 | // 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.
62 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
63 | }
64 |
65 |
66 | - (void)applicationDidEnterBackground:(UIApplication *)application {
67 | // 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.
68 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
69 | }
70 |
71 |
72 | - (void)applicationWillEnterForeground:(UIApplication *)application {
73 | // 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.
74 | }
75 |
76 |
77 | - (void)applicationDidBecomeActive:(UIApplication *)application {
78 | // 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.
79 | }
80 |
81 |
82 | - (void)applicationWillTerminate:(UIApplication *)application {
83 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
84 | }
85 |
86 |
87 | @end
88 |
--------------------------------------------------------------------------------
/XLPopGestureDemo/XLPopGestureDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 3336C4CF1E8CA1B700631AAC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3336C4CE1E8CA1B700631AAC /* main.m */; };
11 | 3336C4D21E8CA1B700631AAC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3336C4D11E8CA1B700631AAC /* AppDelegate.m */; };
12 | 3336C4DA1E8CA1B700631AAC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3336C4D91E8CA1B700631AAC /* Assets.xcassets */; };
13 | 3336C4DD1E8CA1B700631AAC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3336C4DB1E8CA1B700631AAC /* LaunchScreen.storyboard */; };
14 | 3336C4E71E8CA1C100631AAC /* UINavigationController+XLPopGesture.m in Sources */ = {isa = PBXBuildFile; fileRef = 3336C4E61E8CA1C100631AAC /* UINavigationController+XLPopGesture.m */; };
15 | 3336C4EA1E8CA1E700631AAC /* XLOneViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3336C4E91E8CA1E700631AAC /* XLOneViewController.m */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | 3336C4CA1E8CA1B700631AAC /* XLPopGestureDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XLPopGestureDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
20 | 3336C4CE1E8CA1B700631AAC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
21 | 3336C4D01E8CA1B700631AAC /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
22 | 3336C4D11E8CA1B700631AAC /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
23 | 3336C4D91E8CA1B700631AAC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
24 | 3336C4DC1E8CA1B700631AAC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
25 | 3336C4DE1E8CA1B700631AAC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
26 | 3336C4E51E8CA1C100631AAC /* UINavigationController+XLPopGesture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UINavigationController+XLPopGesture.h"; sourceTree = ""; };
27 | 3336C4E61E8CA1C100631AAC /* UINavigationController+XLPopGesture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UINavigationController+XLPopGesture.m"; sourceTree = ""; };
28 | 3336C4E81E8CA1E700631AAC /* XLOneViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XLOneViewController.h; sourceTree = ""; };
29 | 3336C4E91E8CA1E700631AAC /* XLOneViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XLOneViewController.m; sourceTree = ""; };
30 | /* End PBXFileReference section */
31 |
32 | /* Begin PBXFrameworksBuildPhase section */
33 | 3336C4C71E8CA1B700631AAC /* Frameworks */ = {
34 | isa = PBXFrameworksBuildPhase;
35 | buildActionMask = 2147483647;
36 | files = (
37 | );
38 | runOnlyForDeploymentPostprocessing = 0;
39 | };
40 | /* End PBXFrameworksBuildPhase section */
41 |
42 | /* Begin PBXGroup section */
43 | 3336C4C11E8CA1B700631AAC = {
44 | isa = PBXGroup;
45 | children = (
46 | 3336C4CC1E8CA1B700631AAC /* XLPopGestureDemo */,
47 | 3336C4CB1E8CA1B700631AAC /* Products */,
48 | );
49 | sourceTree = "";
50 | };
51 | 3336C4CB1E8CA1B700631AAC /* Products */ = {
52 | isa = PBXGroup;
53 | children = (
54 | 3336C4CA1E8CA1B700631AAC /* XLPopGestureDemo.app */,
55 | );
56 | name = Products;
57 | sourceTree = "";
58 | };
59 | 3336C4CC1E8CA1B700631AAC /* XLPopGestureDemo */ = {
60 | isa = PBXGroup;
61 | children = (
62 | 3336C4E41E8CA1C100631AAC /* XLPopGesture */,
63 | 3336C4E81E8CA1E700631AAC /* XLOneViewController.h */,
64 | 3336C4E91E8CA1E700631AAC /* XLOneViewController.m */,
65 | 3336C4D01E8CA1B700631AAC /* AppDelegate.h */,
66 | 3336C4D11E8CA1B700631AAC /* AppDelegate.m */,
67 | 3336C4D91E8CA1B700631AAC /* Assets.xcassets */,
68 | 3336C4DB1E8CA1B700631AAC /* LaunchScreen.storyboard */,
69 | 3336C4DE1E8CA1B700631AAC /* Info.plist */,
70 | 3336C4CD1E8CA1B700631AAC /* Supporting Files */,
71 | );
72 | path = XLPopGestureDemo;
73 | sourceTree = "";
74 | };
75 | 3336C4CD1E8CA1B700631AAC /* Supporting Files */ = {
76 | isa = PBXGroup;
77 | children = (
78 | 3336C4CE1E8CA1B700631AAC /* main.m */,
79 | );
80 | name = "Supporting Files";
81 | sourceTree = "";
82 | };
83 | 3336C4E41E8CA1C100631AAC /* XLPopGesture */ = {
84 | isa = PBXGroup;
85 | children = (
86 | 3336C4E51E8CA1C100631AAC /* UINavigationController+XLPopGesture.h */,
87 | 3336C4E61E8CA1C100631AAC /* UINavigationController+XLPopGesture.m */,
88 | );
89 | name = XLPopGesture;
90 | path = ../../XLPopGesture;
91 | sourceTree = "";
92 | };
93 | /* End PBXGroup section */
94 |
95 | /* Begin PBXNativeTarget section */
96 | 3336C4C91E8CA1B700631AAC /* XLPopGestureDemo */ = {
97 | isa = PBXNativeTarget;
98 | buildConfigurationList = 3336C4E11E8CA1B700631AAC /* Build configuration list for PBXNativeTarget "XLPopGestureDemo" */;
99 | buildPhases = (
100 | 3336C4C61E8CA1B700631AAC /* Sources */,
101 | 3336C4C71E8CA1B700631AAC /* Frameworks */,
102 | 3336C4C81E8CA1B700631AAC /* Resources */,
103 | );
104 | buildRules = (
105 | );
106 | dependencies = (
107 | );
108 | name = XLPopGestureDemo;
109 | productName = XLPopGestureDemo;
110 | productReference = 3336C4CA1E8CA1B700631AAC /* XLPopGestureDemo.app */;
111 | productType = "com.apple.product-type.application";
112 | };
113 | /* End PBXNativeTarget section */
114 |
115 | /* Begin PBXProject section */
116 | 3336C4C21E8CA1B700631AAC /* Project object */ = {
117 | isa = PBXProject;
118 | attributes = {
119 | LastUpgradeCheck = 0830;
120 | ORGANIZATIONNAME = "cai cai";
121 | TargetAttributes = {
122 | 3336C4C91E8CA1B700631AAC = {
123 | CreatedOnToolsVersion = 8.3;
124 | DevelopmentTeam = 4836KSGVBA;
125 | ProvisioningStyle = Automatic;
126 | };
127 | };
128 | };
129 | buildConfigurationList = 3336C4C51E8CA1B700631AAC /* Build configuration list for PBXProject "XLPopGestureDemo" */;
130 | compatibilityVersion = "Xcode 3.2";
131 | developmentRegion = English;
132 | hasScannedForEncodings = 0;
133 | knownRegions = (
134 | en,
135 | Base,
136 | );
137 | mainGroup = 3336C4C11E8CA1B700631AAC;
138 | productRefGroup = 3336C4CB1E8CA1B700631AAC /* Products */;
139 | projectDirPath = "";
140 | projectRoot = "";
141 | targets = (
142 | 3336C4C91E8CA1B700631AAC /* XLPopGestureDemo */,
143 | );
144 | };
145 | /* End PBXProject section */
146 |
147 | /* Begin PBXResourcesBuildPhase section */
148 | 3336C4C81E8CA1B700631AAC /* Resources */ = {
149 | isa = PBXResourcesBuildPhase;
150 | buildActionMask = 2147483647;
151 | files = (
152 | 3336C4DD1E8CA1B700631AAC /* LaunchScreen.storyboard in Resources */,
153 | 3336C4DA1E8CA1B700631AAC /* Assets.xcassets in Resources */,
154 | );
155 | runOnlyForDeploymentPostprocessing = 0;
156 | };
157 | /* End PBXResourcesBuildPhase section */
158 |
159 | /* Begin PBXSourcesBuildPhase section */
160 | 3336C4C61E8CA1B700631AAC /* Sources */ = {
161 | isa = PBXSourcesBuildPhase;
162 | buildActionMask = 2147483647;
163 | files = (
164 | 3336C4D21E8CA1B700631AAC /* AppDelegate.m in Sources */,
165 | 3336C4EA1E8CA1E700631AAC /* XLOneViewController.m in Sources */,
166 | 3336C4CF1E8CA1B700631AAC /* main.m in Sources */,
167 | 3336C4E71E8CA1C100631AAC /* UINavigationController+XLPopGesture.m in Sources */,
168 | );
169 | runOnlyForDeploymentPostprocessing = 0;
170 | };
171 | /* End PBXSourcesBuildPhase section */
172 |
173 | /* Begin PBXVariantGroup section */
174 | 3336C4DB1E8CA1B700631AAC /* LaunchScreen.storyboard */ = {
175 | isa = PBXVariantGroup;
176 | children = (
177 | 3336C4DC1E8CA1B700631AAC /* Base */,
178 | );
179 | name = LaunchScreen.storyboard;
180 | sourceTree = "";
181 | };
182 | /* End PBXVariantGroup section */
183 |
184 | /* Begin XCBuildConfiguration section */
185 | 3336C4DF1E8CA1B700631AAC /* Debug */ = {
186 | isa = XCBuildConfiguration;
187 | buildSettings = {
188 | ALWAYS_SEARCH_USER_PATHS = NO;
189 | CLANG_ANALYZER_NONNULL = YES;
190 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
191 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
192 | CLANG_CXX_LIBRARY = "libc++";
193 | CLANG_ENABLE_MODULES = YES;
194 | CLANG_ENABLE_OBJC_ARC = YES;
195 | CLANG_WARN_BOOL_CONVERSION = YES;
196 | CLANG_WARN_CONSTANT_CONVERSION = YES;
197 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
198 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
199 | CLANG_WARN_EMPTY_BODY = YES;
200 | CLANG_WARN_ENUM_CONVERSION = YES;
201 | CLANG_WARN_INFINITE_RECURSION = YES;
202 | CLANG_WARN_INT_CONVERSION = YES;
203 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
204 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
205 | CLANG_WARN_UNREACHABLE_CODE = YES;
206 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
207 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
208 | COPY_PHASE_STRIP = NO;
209 | DEBUG_INFORMATION_FORMAT = dwarf;
210 | ENABLE_STRICT_OBJC_MSGSEND = YES;
211 | ENABLE_TESTABILITY = YES;
212 | GCC_C_LANGUAGE_STANDARD = gnu99;
213 | GCC_DYNAMIC_NO_PIC = NO;
214 | GCC_NO_COMMON_BLOCKS = YES;
215 | GCC_OPTIMIZATION_LEVEL = 0;
216 | GCC_PREPROCESSOR_DEFINITIONS = (
217 | "DEBUG=1",
218 | "$(inherited)",
219 | );
220 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
221 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
222 | GCC_WARN_UNDECLARED_SELECTOR = YES;
223 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
224 | GCC_WARN_UNUSED_FUNCTION = YES;
225 | GCC_WARN_UNUSED_VARIABLE = YES;
226 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
227 | MTL_ENABLE_DEBUG_INFO = YES;
228 | ONLY_ACTIVE_ARCH = YES;
229 | SDKROOT = iphoneos;
230 | };
231 | name = Debug;
232 | };
233 | 3336C4E01E8CA1B700631AAC /* Release */ = {
234 | isa = XCBuildConfiguration;
235 | buildSettings = {
236 | ALWAYS_SEARCH_USER_PATHS = NO;
237 | CLANG_ANALYZER_NONNULL = YES;
238 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
240 | CLANG_CXX_LIBRARY = "libc++";
241 | CLANG_ENABLE_MODULES = YES;
242 | CLANG_ENABLE_OBJC_ARC = YES;
243 | CLANG_WARN_BOOL_CONVERSION = YES;
244 | CLANG_WARN_CONSTANT_CONVERSION = YES;
245 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
246 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
247 | CLANG_WARN_EMPTY_BODY = YES;
248 | CLANG_WARN_ENUM_CONVERSION = YES;
249 | CLANG_WARN_INFINITE_RECURSION = YES;
250 | CLANG_WARN_INT_CONVERSION = YES;
251 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
252 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
253 | CLANG_WARN_UNREACHABLE_CODE = YES;
254 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
255 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
256 | COPY_PHASE_STRIP = NO;
257 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
258 | ENABLE_NS_ASSERTIONS = NO;
259 | ENABLE_STRICT_OBJC_MSGSEND = YES;
260 | GCC_C_LANGUAGE_STANDARD = gnu99;
261 | GCC_NO_COMMON_BLOCKS = YES;
262 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
263 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
264 | GCC_WARN_UNDECLARED_SELECTOR = YES;
265 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
266 | GCC_WARN_UNUSED_FUNCTION = YES;
267 | GCC_WARN_UNUSED_VARIABLE = YES;
268 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
269 | MTL_ENABLE_DEBUG_INFO = NO;
270 | SDKROOT = iphoneos;
271 | VALIDATE_PRODUCT = YES;
272 | };
273 | name = Release;
274 | };
275 | 3336C4E21E8CA1B700631AAC /* Debug */ = {
276 | isa = XCBuildConfiguration;
277 | buildSettings = {
278 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
279 | DEVELOPMENT_TEAM = 4836KSGVBA;
280 | INFOPLIST_FILE = XLPopGestureDemo/Info.plist;
281 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
282 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
283 | PRODUCT_BUNDLE_IDENTIFIER = com.xlit.XLPopGestureDemo;
284 | PRODUCT_NAME = "$(TARGET_NAME)";
285 | };
286 | name = Debug;
287 | };
288 | 3336C4E31E8CA1B700631AAC /* Release */ = {
289 | isa = XCBuildConfiguration;
290 | buildSettings = {
291 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
292 | DEVELOPMENT_TEAM = 4836KSGVBA;
293 | INFOPLIST_FILE = XLPopGestureDemo/Info.plist;
294 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
295 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
296 | PRODUCT_BUNDLE_IDENTIFIER = com.xlit.XLPopGestureDemo;
297 | PRODUCT_NAME = "$(TARGET_NAME)";
298 | };
299 | name = Release;
300 | };
301 | /* End XCBuildConfiguration section */
302 |
303 | /* Begin XCConfigurationList section */
304 | 3336C4C51E8CA1B700631AAC /* Build configuration list for PBXProject "XLPopGestureDemo" */ = {
305 | isa = XCConfigurationList;
306 | buildConfigurations = (
307 | 3336C4DF1E8CA1B700631AAC /* Debug */,
308 | 3336C4E01E8CA1B700631AAC /* Release */,
309 | );
310 | defaultConfigurationIsVisible = 0;
311 | defaultConfigurationName = Release;
312 | };
313 | 3336C4E11E8CA1B700631AAC /* Build configuration list for PBXNativeTarget "XLPopGestureDemo" */ = {
314 | isa = XCConfigurationList;
315 | buildConfigurations = (
316 | 3336C4E21E8CA1B700631AAC /* Debug */,
317 | 3336C4E31E8CA1B700631AAC /* Release */,
318 | );
319 | defaultConfigurationIsVisible = 0;
320 | };
321 | /* End XCConfigurationList section */
322 | };
323 | rootObject = 3336C4C21E8CA1B700631AAC /* Project object */;
324 | }
325 |
--------------------------------------------------------------------------------
/XLPopGesture/UINavigationController+XLPopGesture.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2016-2017 cctomato ( https://github.com/cctomato )
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | #import "UINavigationController+XLPopGesture.h"
24 | #import
25 |
26 | @interface XLPopGestureDelegate : NSObject
27 | @property (nonatomic, weak) UINavigationController *navigationController;
28 | @end
29 |
30 | @implementation XLPopGestureDelegate
31 |
32 | - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer
33 | {
34 | if (self.navigationController.viewControllers.count <= 1) {
35 | return NO;
36 | }
37 |
38 | UIViewController *topViewController = [self.navigationController.viewControllers lastObject];
39 | if (topViewController.xl_prefersDisablePop) {
40 | return NO;
41 | }
42 |
43 | if ([[self.navigationController valueForKey:@"_isTransitioning"] boolValue]) {
44 | return NO;
45 | }
46 |
47 | CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view];
48 | if (translation.x <= 0) {
49 | return NO;
50 | }
51 |
52 | return YES;
53 | }
54 |
55 | @end
56 |
57 | @interface XLViewControllerAnimatedTransitioningDelegate : NSObject
58 |
59 | @property (nonatomic, assign) UINavigationControllerOperation operation;
60 |
61 | @property (nonatomic, weak) UIViewController *fromViewController;
62 |
63 | @property (nonatomic, weak) UIViewController *toViewController;
64 |
65 | - (instancetype)initWithNavigationControllerOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController;
66 |
67 | @end
68 |
69 | @implementation XLViewControllerAnimatedTransitioningDelegate
70 |
71 | - (instancetype)initWithNavigationControllerOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController
72 | {
73 | self = [super init];
74 | if (self) {
75 | self.operation = operation;
76 | self.fromViewController = fromViewController;
77 | self.toViewController = toViewController;
78 | }
79 | return self;
80 | }
81 |
82 | - (NSTimeInterval)transitionDuration:(id)transitionContext
83 | {
84 | return 0.5;
85 | }
86 |
87 | - (void)animateTransition:(id)transitionContext
88 | {
89 | UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
90 | UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
91 |
92 | NSTimeInterval duration = [self transitionDuration:transitionContext];
93 | // if (self.operation == UINavigationControllerOperationPush) {
94 | // [[transitionContext containerView] addSubview:fromViewController.xl_snapshot];
95 | // fromViewController.view.hidden = YES;
96 | //
97 | // CGRect frame = [transitionContext finalFrameForViewController:toViewController];
98 | // toViewController.view.frame = CGRectOffset(frame, CGRectGetWidth(frame), 0);
99 | // [[transitionContext containerView] addSubview:toViewController.view];
100 | //
101 | // [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
102 | // fromViewController.xl_snapshot.alpha = 0.0;
103 | // fromViewController.xl_snapshot.frame = CGRectInset(fromViewController.view.frame, 20, 20);
104 | // toViewController.view.frame = CGRectOffset(toViewController.view.frame, -CGRectGetWidth(toViewController.view.frame), 0);
105 | // } completion:^(BOOL finished) {
106 | // fromViewController.view.hidden = NO;
107 | // [fromViewController.xl_snapshot removeFromSuperview];
108 | // [transitionContext completeTransition:YES];
109 | // }];
110 | // }
111 | if (self.operation == UINavigationControllerOperationPop) {
112 | [UIApplication sharedApplication].keyWindow.backgroundColor = [UIColor blackColor];
113 |
114 | fromViewController.xl_snapshot.frame = fromViewController.navigationController.view.bounds;
115 |
116 | BOOL tabBarHidden = fromViewController.tabBarController.tabBar.hidden;
117 |
118 | fromViewController.navigationController.navigationBar.hidden = YES;
119 | fromViewController.tabBarController.tabBar.hidden = YES;
120 |
121 | toViewController.xl_snapshot.alpha = 0.5;
122 | if (toViewController.navigationController.xl_prefersOpenPopEffects) {
123 | toViewController.xl_snapshot.transform = CGAffineTransformMakeScale(0.95, 0.95);
124 | }
125 |
126 | UIView *toViewWrapperView = [[UIView alloc] initWithFrame:[transitionContext containerView].bounds];
127 | [toViewWrapperView addSubview:toViewController.view];
128 | toViewWrapperView.hidden = YES;
129 |
130 | [[transitionContext containerView] addSubview:toViewWrapperView];
131 | [[transitionContext containerView] addSubview:toViewController.xl_snapshot];
132 | [[transitionContext containerView] addSubview:fromViewController.xl_snapshot];
133 |
134 | [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
135 | fromViewController.view.frame = CGRectOffset(fromViewController.view.frame, CGRectGetWidth(fromViewController.view.frame), 0);
136 | fromViewController.xl_snapshot.frame = CGRectOffset(fromViewController.xl_snapshot.frame, CGRectGetWidth(fromViewController.xl_snapshot.frame), 0);
137 |
138 | toViewController.xl_snapshot.alpha = 1.0;
139 | toViewController.xl_snapshot.transform = CGAffineTransformIdentity;
140 | } completion:^(BOOL finished) {
141 | [UIApplication sharedApplication].keyWindow.backgroundColor = [UIColor whiteColor];
142 | toViewController.navigationController.navigationBar.hidden = NO;
143 | toViewController.tabBarController.tabBar.hidden = tabBarHidden;
144 | [fromViewController.xl_snapshot removeFromSuperview];
145 | [toViewController.xl_snapshot removeFromSuperview];
146 | [toViewWrapperView removeFromSuperview];
147 | if (![transitionContext transitionWasCancelled]) {
148 | for (UIView *subView in toViewWrapperView.subviews) {
149 | [[transitionContext containerView] addSubview:subView];
150 | }
151 | }
152 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
153 | }];
154 | }
155 | }
156 |
157 | @end
158 |
159 | @interface XLPopNavgationDelegate : NSObject
160 |
161 | @end
162 |
163 | @implementation XLPopNavgationDelegate
164 |
165 | - (id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(XLViewControllerAnimatedTransitioningDelegate *)animationController
166 | {
167 | return animationController.fromViewController.navigationController.xl_interactivePopTransition;
168 | }
169 |
170 | - (id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
171 | {
172 | if (fromVC.navigationController.xl_interactivePopTransition) {
173 | return [[XLViewControllerAnimatedTransitioningDelegate alloc] initWithNavigationControllerOperation:operation fromViewController:fromVC toViewController:toVC];
174 | }
175 | return nil;
176 | }
177 |
178 | @end
179 |
180 | typedef void (^XLViewControllerWillAppearInjectBlock)(UIViewController *viewController, BOOL animated);
181 |
182 | @interface UIViewController (XLPrivate)
183 |
184 | @property (nonatomic, copy) XLViewControllerWillAppearInjectBlock xl_willAppearInjectBlock;
185 |
186 | @end
187 |
188 | @implementation UIViewController (XLPrivate)
189 |
190 | + (void)load
191 | {
192 | Method originalMethod = class_getInstanceMethod(self, @selector(viewWillAppear:));
193 | Method swizzledMethod = class_getInstanceMethod(self, @selector(xl_viewWillAppear:));
194 | method_exchangeImplementations(originalMethod, swizzledMethod);
195 |
196 | Method disOriginalMethod = class_getInstanceMethod(self, @selector(viewWillDisappear:));
197 | Method disSwizzledMethod = class_getInstanceMethod(self, @selector(xl_viewWillDisappear:));
198 | method_exchangeImplementations(disOriginalMethod, disSwizzledMethod);
199 | }
200 |
201 | - (void)xl_viewWillDisappear:(BOOL)animated
202 | {
203 | [self xl_viewWillDisappear:animated];
204 |
205 | if ([self isMovingFromParentViewController]) {
206 | self.xl_snapshot = [[UIApplication sharedApplication].keyWindow snapshotViewAfterScreenUpdates:NO];
207 | }
208 | }
209 |
210 | - (void)xl_viewWillAppear:(BOOL)animated
211 | {
212 | [self xl_viewWillAppear:animated];
213 |
214 | if (self.xl_willAppearInjectBlock) {
215 | self.xl_willAppearInjectBlock(self, animated);
216 | }
217 | }
218 |
219 | - (XLViewControllerWillAppearInjectBlock)xl_willAppearInjectBlock
220 | {
221 | return objc_getAssociatedObject(self, _cmd);
222 | }
223 |
224 | - (void)setXl_willAppearInjectBlock:(XLViewControllerWillAppearInjectBlock)xl_willAppearInjectBlock
225 | {
226 | objc_setAssociatedObject(self, @selector(xl_willAppearInjectBlock), xl_willAppearInjectBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
227 | }
228 |
229 | @end
230 |
231 | @implementation UINavigationController (XLPopGesture)
232 |
233 | + (void)load
234 | {
235 | Method originalMethod = class_getInstanceMethod(self, @selector(pushViewController:animated:));
236 | Method swizzledMethod = class_getInstanceMethod(self, @selector(xl_pushViewController:animated:));
237 | method_exchangeImplementations(originalMethod, swizzledMethod);
238 | }
239 |
240 | - (void)xl_pushViewController:(UIViewController *)viewController animated:(BOOL)animated
241 | {
242 | if (!self.delegate) {
243 | self.delegate = self.xl_popTransitionDelegate;
244 | }
245 |
246 | UIViewController *lastController = [self.viewControllers lastObject];
247 | if (lastController.tabBarController && self.xl_prefersHiddenTabBar) {
248 | [viewController setHidesBottomBarWhenPushed:YES];
249 | }
250 | lastController.xl_snapshot = [[UIApplication sharedApplication].keyWindow snapshotViewAfterScreenUpdates:NO];
251 |
252 | if (![self.interactivePopGestureRecognizer.view.gestureRecognizers containsObject:self.xl_popRecoginzer]) {
253 |
254 | [self.interactivePopGestureRecognizer.view addGestureRecognizer:self.xl_popRecoginzer];
255 |
256 | self.xl_popRecoginzer.delegate = self.xl_popGestureDelegate;
257 | [self.xl_popRecoginzer addTarget:self action:@selector(handlePopRecognizer:)];
258 |
259 | self.interactivePopGestureRecognizer.enabled = NO;
260 |
261 | }
262 |
263 | [self xl_setupViewControllerBasedNavigationBarAppearanceIfNeeded:viewController];
264 |
265 | [self xl_pushViewController:viewController animated:animated];
266 | }
267 |
268 | - (void)xl_setupViewControllerBasedNavigationBarAppearanceIfNeeded:(UIViewController *)appearingViewController
269 | {
270 | if (!self.xl_viewControllerBasedNavigationBarAppearanceEnabled) {
271 | return;
272 | }
273 |
274 | __weak typeof(self) weakSelf = self;
275 | XLViewControllerWillAppearInjectBlock block = ^(UIViewController *viewController, BOOL animated) {
276 | __strong typeof(weakSelf) strongSelf = weakSelf;
277 | if (strongSelf) {
278 | [strongSelf setNavigationBarHidden:viewController.xl_prefersNavigationBarHidden animated:animated];
279 | }
280 | };
281 |
282 | appearingViewController.xl_willAppearInjectBlock = block;
283 | UIViewController *disapperingViewController = self.viewControllers.lastObject;
284 | if (disapperingViewController && !disapperingViewController.xl_willAppearInjectBlock) {
285 | disapperingViewController.xl_willAppearInjectBlock = block;
286 | }
287 | }
288 |
289 | - (void)handlePopRecognizer:(UIPanGestureRecognizer *)recognizer
290 | {
291 | CGFloat progress = [recognizer translationInView:recognizer.view].x / [UIScreen mainScreen].bounds.size.width;
292 | progress = MIN(1.0, MAX(0.0, progress));
293 |
294 | if (recognizer.state == UIGestureRecognizerStateBegan) {
295 | self.xl_interactivePopTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
296 | [self popViewControllerAnimated:YES];
297 | } else if (recognizer.state == UIGestureRecognizerStateChanged) {
298 | [self.xl_interactivePopTransition updateInteractiveTransition:progress];
299 | } else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {
300 | if (progress > 0.2) {
301 | [self.xl_interactivePopTransition finishInteractiveTransition];
302 | } else {
303 | [self.xl_interactivePopTransition cancelInteractiveTransition];
304 | }
305 | self.xl_interactivePopTransition = nil;
306 | }
307 | }
308 |
309 | - (UIPanGestureRecognizer *)xl_popRecoginzer
310 | {
311 | UIPanGestureRecognizer *panGestureRecognizer = objc_getAssociatedObject(self, _cmd);
312 |
313 | if (!panGestureRecognizer) {
314 | panGestureRecognizer = [[UIPanGestureRecognizer alloc] init];
315 | panGestureRecognizer.maximumNumberOfTouches = 1;
316 |
317 | objc_setAssociatedObject(self, _cmd, panGestureRecognizer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
318 | }
319 |
320 | return panGestureRecognizer;
321 | }
322 |
323 | - (XLPopNavgationDelegate *)xl_popTransitionDelegate
324 | {
325 | XLPopNavgationDelegate *delegate = objc_getAssociatedObject(self, _cmd);
326 |
327 | if (!delegate) {
328 | delegate = [[XLPopNavgationDelegate alloc] init];
329 |
330 | objc_setAssociatedObject(self, _cmd, delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
331 | }
332 |
333 | return delegate;
334 | }
335 |
336 | - (XLPopGestureDelegate *)xl_popGestureDelegate
337 | {
338 | XLPopGestureDelegate *delegate = objc_getAssociatedObject(self, _cmd);
339 |
340 | if (!delegate) {
341 | delegate = [[XLPopGestureDelegate alloc] init];
342 | delegate.navigationController = self;
343 |
344 | objc_setAssociatedObject(self, _cmd, delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
345 | }
346 |
347 | return delegate;
348 | }
349 |
350 | - (BOOL)xl_viewControllerBasedNavigationBarAppearanceEnabled
351 | {
352 | NSNumber *number = objc_getAssociatedObject(self, _cmd);
353 | if (number) {
354 | return number.boolValue;
355 | }
356 | self.xl_viewControllerBasedNavigationBarAppearanceEnabled = YES;
357 | return YES;
358 | }
359 |
360 | - (void)setXl_viewControllerBasedNavigationBarAppearanceEnabled:(BOOL)enable
361 | {
362 | SEL key = @selector(xl_viewControllerBasedNavigationBarAppearanceEnabled);
363 | objc_setAssociatedObject(self, key, @(enable), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
364 | }
365 |
366 | - (UIPercentDrivenInteractiveTransition *)xl_interactivePopTransition
367 | {
368 | return objc_getAssociatedObject(self, _cmd);
369 | }
370 |
371 | - (void)setXl_interactivePopTransition:(UIPercentDrivenInteractiveTransition *)interactivePopTransition
372 | {
373 | objc_setAssociatedObject(self, @selector(xl_interactivePopTransition), interactivePopTransition, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
374 | }
375 |
376 | - (BOOL)xl_prefersHiddenTabBar
377 | {
378 | NSNumber *number = objc_getAssociatedObject(self, _cmd);
379 | if (number) {
380 | return [number boolValue];
381 | }
382 | return YES;
383 | }
384 |
385 | - (void)setXl_prefersHiddenTabBar:(BOOL)prefersHiddenTabBar
386 | {
387 | objc_setAssociatedObject(self, @selector(xl_prefersHiddenTabBar), @(prefersHiddenTabBar), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
388 | }
389 |
390 | - (BOOL)xl_prefersOpenPopEffects
391 | {
392 | NSNumber *number = objc_getAssociatedObject(self, _cmd);
393 | if (number) {
394 | return [number boolValue];
395 | }
396 | return YES;
397 | }
398 |
399 | - (void)setXl_prefersOpenPopEffects:(BOOL)prefersOpenPopEffects
400 | {
401 | objc_setAssociatedObject(self, @selector(xl_prefersOpenPopEffects), @(prefersOpenPopEffects), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
402 | }
403 |
404 | @end
405 |
406 | @implementation UIViewController (XLPopGesture)
407 |
408 | - (BOOL)xl_prefersDisablePop
409 | {
410 | return [objc_getAssociatedObject(self, _cmd) boolValue];
411 | }
412 |
413 | - (void)setXl_prefersDisablePop:(BOOL)disable
414 | {
415 | objc_setAssociatedObject(self, @selector(xl_prefersDisablePop), @(disable), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
416 | }
417 |
418 | - (BOOL)xl_prefersNavigationBarHidden
419 | {
420 | return [objc_getAssociatedObject(self, _cmd) boolValue];
421 | }
422 |
423 | - (void)setXl_prefersNavigationBarHidden:(BOOL)hidden
424 | {
425 | objc_setAssociatedObject(self, @selector(xl_prefersNavigationBarHidden), @(hidden), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
426 | }
427 |
428 | - (UIView *)xl_snapshot
429 | {
430 | return objc_getAssociatedObject(self, _cmd);
431 | }
432 |
433 | - (void)setXl_snapshot:(UIView *)snapshot
434 | {
435 | objc_setAssociatedObject(self, @selector(xl_snapshot), snapshot, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
436 | }
437 |
438 | @end
439 |
--------------------------------------------------------------------------------