diff --git a/FDFullscreenPopGesture.podspec b/FDFullscreenPopGesture.podspec index 9e4e90d..495cb39 100644 --- a/FDFullscreenPopGesture.podspec +++ b/FDFullscreenPopGesture.podspec @@ -1,7 +1,8 @@ + Pod::Spec.new do |s| s.name = "FDFullscreenPopGesture" - s.version = "1.1" + s.version = "1.1.1" s.summary = "An UINavigationController's category to enable fullscreen pop gesture in iOS7+ system style with an AOP useage." s.description = "An UINavigationController's category to enable fullscreen pop gesture in iOS7+ system style with an AOP useage. Just pod in 2 files and no need for any setups." s.homepage = "https://github.com/forkingdog/FDFullscreenPopGesture" @@ -13,9 +14,9 @@ Pod::Spec.new do |s| # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # s.platform = :ios, "7.0" # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # - s.source = { :git => "https://github.com/forkingdog/FDFullscreenPopGesture.git", :tag => "1.1" } + s.source = { :git => "https://github.com/forkingdog/FDFullscreenPopGesture.git", :tag => "1.1.1" } # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # s.source_files = "FDFullscreenPopGesture/*.{h,m}" # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # s.requires_arc = true -end +end \ No newline at end of file diff --git a/FDFullscreenPopGesture/UINavigationController+FDFullscreenPopGesture.m b/FDFullscreenPopGesture/UINavigationController+FDFullscreenPopGesture.m index 914f217..ebdbd99 100644 --- a/FDFullscreenPopGesture/UINavigationController+FDFullscreenPopGesture.m +++ b/FDFullscreenPopGesture/UINavigationController+FDFullscreenPopGesture.m @@ -21,8 +21,61 @@ // SOFTWARE. #import "UINavigationController+FDFullscreenPopGesture.h" +#import #import +@interface FDPanGestureRecognizer : UIPanGestureRecognizer + +@property (nonatomic, strong, readonly) UIEvent *event; + +- (CGPoint)beganLocationInView:(UIView *)view; + +@end + +@interface FDPanGestureRecognizer () + +@property (strong, nonatomic) UIEvent *event; +@property (assign, nonatomic) CGPoint beganLocation; +@property (assign, nonatomic) NSTimeInterval beganTime; + +@end + +@implementation FDPanGestureRecognizer + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ + UITouch *touch = [touches anyObject]; + self.event = event; + self.beganTime = event.timestamp; + self.beganLocation = [touch locationInView:self.view]; + [super touchesBegan:touches withEvent:event]; +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + if (self.state == UIGestureRecognizerStatePossible && event.timestamp - self.beganTime > 0.3) { + self.state = UIGestureRecognizerStateFailed; + return; + } + [super touchesMoved:touches withEvent:event]; +} + +- (void)reset +{ + self.event = nil; + self.beganTime = 0; + self.beganLocation = CGPointZero; + [super reset]; +} + +- (CGPoint)beganLocationInView:(UIView *)view +{ + return [view convertPoint:self.beganLocation fromView:self.view]; +} + +@end + + @interface _FDFullscreenPopGestureRecognizerDelegate : NSObject @property (nonatomic, weak) UINavigationController *navigationController; @@ -50,7 +103,7 @@ - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer if (maxAllowedInitialDistance > 0 && beginningLocation.x > maxAllowedInitialDistance) { return NO; } - + // Ignore pan gesture when the navigation controller is currently in transition. if ([[self.navigationController valueForKey:@"_isTransitioning"] boolValue]) { return NO; @@ -65,6 +118,62 @@ - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer return YES; } +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer +{ + + // Ignore when no view controller is pushed into the navigation stack. + if (self.navigationController.viewControllers.count <= 1) { + return NO; + } + + // Ignore when the active view controller doesn't allow interactive pop. + UIViewController *topViewController = self.navigationController.viewControllers.lastObject; + if (topViewController.fd_interactivePopDisabled) { + return NO; + } + + // Ignore when the beginning location is beyond max allowed initial distance to left edge. + CGPoint beginningLocation = [gestureRecognizer locationInView:gestureRecognizer.view]; + CGFloat maxAllowedInitialDistance = topViewController.fd_interactivePopMaxAllowedInitialDistanceToLeftEdge; + if (maxAllowedInitialDistance > 0 && beginningLocation.x > maxAllowedInitialDistance) { + return NO; + } + + // Ignore pan gesture when the navigation controller is currently in transition. + if ([[self.navigationController valueForKey:@"_isTransitioning"] boolValue]) { + return NO; + } + + FDPanGestureRecognizer* fd_gestureRecognizer = (FDPanGestureRecognizer *)gestureRecognizer; + // Prevent calling the handler when the gesture begins in an opposite direction. + CGPoint translation = [fd_gestureRecognizer translationInView:fd_gestureRecognizer.view]; + if (translation.x <= 0) { + return NO; + } + + CGPoint touchPoint = [fd_gestureRecognizer beganLocationInView:fd_gestureRecognizer.view]; + // If within thirty hit area on the left, forced back + if (touchPoint.x < 30) { + NSSet *touchs = [fd_gestureRecognizer.event touchesForGestureRecognizer:otherGestureRecognizer]; + [otherGestureRecognizer touchesCancelled:touchs withEvent:fd_gestureRecognizer.event]; + return YES; + } + + // If there are multiple gestures + // And other gestures of view is a scroll view + // If you scroll view scroll to less than zero, the scroll view gesture cancellation effect + if ([[otherGestureRecognizer view] isKindOfClass:[UIScrollView class]]) { + UIScrollView *scrollView = (UIScrollView *)[otherGestureRecognizer view]; + if (scrollView.contentOffset.x <= 0) { + NSSet *touchs = [fd_gestureRecognizer.event touchesForGestureRecognizer:otherGestureRecognizer]; + [otherGestureRecognizer touchesCancelled:touchs withEvent:fd_gestureRecognizer.event]; + return YES; + } + } + + return NO; +} + @end typedef void (^_FDViewControllerWillAppearInjectBlock)(UIViewController *viewController, BOOL animated); @@ -150,14 +259,14 @@ - (void)fd_pushViewController:(UIViewController *)viewController animated:(BOOL) // Add our own gesture recognizer to where the onboard screen edge pan gesture recognizer is attached to. [self.interactivePopGestureRecognizer.view addGestureRecognizer:self.fd_fullscreenPopGestureRecognizer]; - + // Forward the gesture events to the private handler of the onboard gesture recognizer. NSArray *internalTargets = [self.interactivePopGestureRecognizer valueForKey:@"targets"]; id internalTarget = [internalTargets.firstObject valueForKey:@"target"]; SEL internalAction = NSSelectorFromString(@"handleNavigationTransition:"); self.fd_fullscreenPopGestureRecognizer.delegate = self.fd_popGestureRecognizerDelegate; [self.fd_fullscreenPopGestureRecognizer addTarget:internalTarget action:internalAction]; - + // Disable the onboard gesture recognizer. self.interactivePopGestureRecognizer.enabled = NO; } @@ -198,7 +307,7 @@ - (void)fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded:(UIViewContro - (_FDFullscreenPopGestureRecognizerDelegate *)fd_popGestureRecognizerDelegate { _FDFullscreenPopGestureRecognizerDelegate *delegate = objc_getAssociatedObject(self, _cmd); - + if (!delegate) { delegate = [[_FDFullscreenPopGestureRecognizerDelegate alloc] init]; delegate.navigationController = self; @@ -211,9 +320,9 @@ - (_FDFullscreenPopGestureRecognizerDelegate *)fd_popGestureRecognizerDelegate - (UIPanGestureRecognizer *)fd_fullscreenPopGestureRecognizer { UIPanGestureRecognizer *panGestureRecognizer = objc_getAssociatedObject(self, _cmd); - + if (!panGestureRecognizer) { - panGestureRecognizer = [[UIPanGestureRecognizer alloc] init]; + panGestureRecognizer = [[FDPanGestureRecognizer alloc] init]; panGestureRecognizer.maximumNumberOfTouches = 1; objc_setAssociatedObject(self, _cmd, panGestureRecognizer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); diff --git a/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo.xcodeproj/project.pbxproj b/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo.xcodeproj/project.pbxproj index 6a5d986..20f1ad3 100644 --- a/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo.xcodeproj/project.pbxproj +++ b/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 3855B3261CCF6EED0072D889 /* FDTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3855B3251CCF6EED0072D889 /* FDTableViewController.m */; }; 4894F4201B183DE3009F44D9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4894F41F1B183DE3009F44D9 /* main.m */; }; 4894F4231B183DE3009F44D9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4894F4221B183DE3009F44D9 /* AppDelegate.m */; }; 4894F4291B183DE3009F44D9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4894F4271B183DE3009F44D9 /* Main.storyboard */; }; @@ -16,6 +17,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 3855B3241CCF6EED0072D889 /* FDTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FDTableViewController.h; sourceTree = ""; }; + 3855B3251CCF6EED0072D889 /* FDTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FDTableViewController.m; sourceTree = ""; }; 4894F41A1B183DE3009F44D9 /* FDFullscreenPopGestureDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FDFullscreenPopGestureDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4894F41E1B183DE3009F44D9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4894F41F1B183DE3009F44D9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; @@ -61,6 +64,8 @@ 4894F4431B183DEF009F44D9 /* FDFullscreenPopGesture */, 4894F4211B183DE3009F44D9 /* AppDelegate.h */, 4894F4221B183DE3009F44D9 /* AppDelegate.m */, + 3855B3241CCF6EED0072D889 /* FDTableViewController.h */, + 3855B3251CCF6EED0072D889 /* FDTableViewController.m */, 4894F4271B183DE3009F44D9 /* Main.storyboard */, 4894F42A1B183DE3009F44D9 /* Images.xcassets */, 4894F42C1B183DE3009F44D9 /* LaunchScreen.xib */, @@ -161,6 +166,7 @@ 4894F4231B183DE3009F44D9 /* AppDelegate.m in Sources */, 4894F4461B183E99009F44D9 /* UINavigationController+FDFullscreenPopGesture.m in Sources */, 4894F4201B183DE3009F44D9 /* main.m in Sources */, + 3855B3261CCF6EED0072D889 /* FDTableViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -305,6 +311,7 @@ 4894F43F1B183DE3009F44D9 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/Base.lproj/LaunchScreen.xib b/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/Base.lproj/LaunchScreen.xib index 8c1bbb7..3c5905a 100644 --- a/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/Base.lproj/LaunchScreen.xib +++ b/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/Base.lproj/LaunchScreen.xib @@ -1,7 +1,8 @@ - + - + + @@ -14,13 +15,13 @@ diff --git a/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/Base.lproj/Main.storyboard b/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/Base.lproj/Main.storyboard index 017c7a7..66a1385 100644 --- a/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/Base.lproj/Main.storyboard +++ b/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/Base.lproj/Main.storyboard @@ -1,8 +1,8 @@ - + - + @@ -11,18 +11,21 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -65,6 +111,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -77,7 +152,7 @@ - - - + @@ -135,7 +210,7 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + diff --git a/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/FDTableViewController.h b/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/FDTableViewController.h new file mode 100644 index 0000000..6bc1b98 --- /dev/null +++ b/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/FDTableViewController.h @@ -0,0 +1,13 @@ +// +// FDTableViewController.h +// FDFullscreenPopGestureDemo +// +// Created by ysghome on 4/26/16. +// Copyright © 2016 forkingdog. All rights reserved. +// + +#import + +@interface FDTableViewController : UITableViewController + +@end diff --git a/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/FDTableViewController.m b/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/FDTableViewController.m new file mode 100644 index 0000000..be31dba --- /dev/null +++ b/FDFullscreenPopGestureDemo/FDFullscreenPopGestureDemo/FDTableViewController.m @@ -0,0 +1,108 @@ +// +// FDTableViewController.m +// FDFullscreenPopGestureDemo +// +// Created by ysghome on 4/26/16. +// Copyright © 2016 forkingdog. All rights reserved. +// + +#import "FDTableViewController.h" +#import "UINavigationController+FDFullscreenPopGesture.h" + +@interface FDTableViewController () + +@end + +@implementation FDTableViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + // Uncomment the following line to preserve selection between presentations. + // self.clearsSelectionOnViewWillAppear = NO; + [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"FDCell"]; + // Uncomment the following line to display an Edit button in the navigation bar for this view controller. + // self.navigationItem.rightBarButtonItem = self.editButtonItem; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 20; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ + return 64; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"FDCell" forIndexPath:indexPath]; + + // Configure the cell... + cell.textLabel.text = [NSString stringWithFormat:@"row is %@", @(indexPath.row)]; + + return cell; +} + +// Override to support conditional editing of the table view. +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{ + return YES; +} + +//设置删除按钮的内容 +- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath{ + return @"删除"; +} + +- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{ + if (editingStyle == UITableViewCellEditingStyleDelete) { + + } +} + +/* +// Override to support editing the table view. +- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { + if (editingStyle == UITableViewCellEditingStyleDelete) { + // Delete the row from the data source + [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; + } else if (editingStyle == UITableViewCellEditingStyleInsert) { + // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view + } +} +*/ + +/* +// Override to support rearranging the table view. +- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { +} +*/ + +/* +// Override to support conditional rearranging of the table view. +- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { + // Return NO if you do not want the item to be re-orderable. + return YES; +} +*/ + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end