From 903edcf3bd5fa05560716c3d1f2b905a20d1c7ec Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Mon, 28 Sep 2015 13:16:37 +0200 Subject: [PATCH] Lock vertical pan gesture in MXPagerView --- .../Parallax/MXParallaxViewController.m | 2 +- .../Parallax/MXRefreshHeaderView.xib | 4 +- .../Simple/MXSimpleViewController.m | 2 +- .../Storyboard/MXNumberViewController.m | 4 +- .../Storyboard/MXStoryboardViewController.m | 5 ++ MXSegmentedPager/MXPagerView.h | 33 ++++++++ MXSegmentedPager/MXPagerView.m | 81 ++++++++++++++----- MXSegmentedPager/MXSegmentedPager.h | 8 -- MXSegmentedPager/MXSegmentedPager.m | 36 ++------- 9 files changed, 114 insertions(+), 61 deletions(-) diff --git a/Example/MXSegmentedPager/Parallax/MXParallaxViewController.m b/Example/MXSegmentedPager/Parallax/MXParallaxViewController.m index 0f5d70bb2..b8e2c8262 100644 --- a/Example/MXSegmentedPager/Parallax/MXParallaxViewController.m +++ b/Example/MXSegmentedPager/Parallax/MXParallaxViewController.m @@ -180,7 +180,7 @@ - (UIView *)segmentedPager:(MXSegmentedPager *)segmentedPager viewForPageAtIndex - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSInteger index = (indexPath.row % 2) + 1; - [self.segmentedPager scrollToPageAtIndex:index animated:YES]; + [self.segmentedPager.pager showPageAtIndex:index animated:YES]; } #pragma -mark diff --git a/Example/MXSegmentedPager/Parallax/MXRefreshHeaderView.xib b/Example/MXSegmentedPager/Parallax/MXRefreshHeaderView.xib index db6671037..cf986d3bd 100644 --- a/Example/MXSegmentedPager/Parallax/MXRefreshHeaderView.xib +++ b/Example/MXSegmentedPager/Parallax/MXRefreshHeaderView.xib @@ -1,8 +1,8 @@ - + - + diff --git a/Example/MXSegmentedPager/Simple/MXSimpleViewController.m b/Example/MXSegmentedPager/Simple/MXSimpleViewController.m index 28c393403..3c255518f 100644 --- a/Example/MXSegmentedPager/Simple/MXSimpleViewController.m +++ b/Example/MXSegmentedPager/Simple/MXSimpleViewController.m @@ -140,7 +140,7 @@ - (UIView *)segmentedPager:(MXSegmentedPager *)segmentedPager viewForPageAtIndex - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSInteger index = (indexPath.row % 2) + 1; - [self.segmentedPager scrollToPageAtIndex:index animated:YES]; + [self.segmentedPager.pager showPageAtIndex:index animated:YES]; } #pragma -mark diff --git a/Example/MXSegmentedPager/Storyboard/MXNumberViewController.m b/Example/MXSegmentedPager/Storyboard/MXNumberViewController.m index 187fd9d03..b8da2aa02 100644 --- a/Example/MXSegmentedPager/Storyboard/MXNumberViewController.m +++ b/Example/MXSegmentedPager/Storyboard/MXNumberViewController.m @@ -17,7 +17,7 @@ @implementation MXNumberViewController - (void)viewDidLoad { [super viewDidLoad]; - self.numberLabel.text = [NSString stringWithFormat:@"Page %li", self.number]; + self.numberLabel.text = [NSString stringWithFormat:@"Page %li", (long)self.number]; } - (void)didReceiveMemoryWarning { @@ -27,7 +27,7 @@ - (void)didReceiveMemoryWarning { - (void)setNumber:(NSInteger)number { _number = number; - self.numberLabel.text = [NSString stringWithFormat:@"Page %li", self.number]; + self.numberLabel.text = [NSString stringWithFormat:@"Page %li", (long)self.number]; } @end diff --git a/Example/MXSegmentedPager/Storyboard/MXStoryboardViewController.m b/Example/MXSegmentedPager/Storyboard/MXStoryboardViewController.m index 4cb668909..f4289a9fa 100644 --- a/Example/MXSegmentedPager/Storyboard/MXStoryboardViewController.m +++ b/Example/MXSegmentedPager/Storyboard/MXStoryboardViewController.m @@ -8,6 +8,7 @@ #import "MXStoryboardViewController.h" #import "MXNumberViewController.h" +#import "MXRefreshHeaderView.h" @implementation MXStoryboardViewController @@ -15,6 +16,10 @@ - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = UIColor.whiteColor; + // Parallax Header + [self.segmentedPager setParallaxHeaderView:[MXRefreshHeaderView instantiateFromNib] mode:VGParallaxHeaderModeFill height:150.f]; + self.segmentedPager.minimumHeaderHeight = 20.f; + // Segmented Control customization self.segmentedPager.segmentedControl.selectionIndicatorLocation = HMSegmentedControlSelectionIndicatorLocationDown; self.segmentedPager.segmentedControl.backgroundColor = [UIColor whiteColor]; diff --git a/MXSegmentedPager/MXPagerView.h b/MXSegmentedPager/MXPagerView.h index 7cca453ec..67d8ad41e 100644 --- a/MXSegmentedPager/MXPagerView.h +++ b/MXSegmentedPager/MXPagerView.h @@ -22,6 +22,38 @@ #import +/** + UIPanGestureRecognizer direction enumeration. + */ +typedef NS_ENUM(NSInteger, MXPanGestureDirection){ + /** No direction. */ + MXPanGestureDirectionNone = 1 << 0, + /** Right direction. */ + MXPanGestureDirectionRight = 1 << 1, + /** Left direction. */ + MXPanGestureDirectionLeft = 1 << 2, + /** Up direction. */ + MXPanGestureDirectionUp = 1 << 3, + /** Down direction. */ + MXPanGestureDirectionDown = 1 << 4 +}; + +/** + UIPanGestureRecognizer category with direction getter. + */ +@interface UIPanGestureRecognizer (Direction) + +/** + Gets the pan gesture direction of the specified view. + + @param view The view + + @return The pan gesture direction. + */ +- (MXPanGestureDirection) directionInView:(nullable __kindof UIView *)view; + +@end + /** The pager transition styles. */ @@ -206,4 +238,5 @@ typedef NS_ENUM(NSInteger, MXPagerViewTransitionStyle) { if the page is reusable (has a reuse identifier), this is called just before the page is returned from the pager view method dequeueReusablePageWithIdentifier:. */ - (void) prepareForReuse; + @end diff --git a/MXSegmentedPager/MXPagerView.m b/MXSegmentedPager/MXPagerView.m index a5469ba37..00dbde7ee 100644 --- a/MXSegmentedPager/MXPagerView.m +++ b/MXSegmentedPager/MXPagerView.m @@ -23,24 +23,15 @@ #import #import "MXPagerView.h" -@implementation UIView (ReuseIdentifier) - -- (NSString *)reuseIdentifier { - return objc_getAssociatedObject(self, @selector(reuseIdentifier)); -} - -- (void)setReuseIdentifier:(NSString *)reuseIdentifier { - objc_setAssociatedObject(self, @selector(reuseIdentifier), reuseIdentifier, OBJC_ASSOCIATION_COPY); -} - -- (void)prepareForReuse { - -} +@interface UIView () +@property (nonatomic, copy) NSString *reuseIdentifier; +@end +@interface MXContentView : UIScrollView @end @interface MXPagerView () -@property (nonatomic, strong) UIScrollView *contentView; +@property (nonatomic, strong) MXContentView *contentView; @property (nonatomic, strong) NSMutableDictionary *pages; @property (nonatomic, strong) NSMutableDictionary *registration; @@ -94,11 +85,12 @@ - (void) reloadData { //Loads the current selected page [self loadPageAtIndex:_index]; + + [self layoutIfNeeded]; } - (void) showPageAtIndex:(NSInteger)index animated:(BOOL)animated { - //The tab behavior disable animation animated = (self.transitionStyle == MXPagerViewTransitionStyleTab)? NO : animated; @@ -124,7 +116,7 @@ - (void)registerClass:(Class)pageClass forPageReuseIdentifier:(NSString *)identi [self.registration setValue:NSStringFromClass(pageClass) forKey:identifier]; } -- (__kindof UIView *)dequeueReusablePageWithIdentifier:(NSString *)identifier { +- (UIView *)dequeueReusablePageWithIdentifier:(NSString *)identifier { for (UIView *page in self.reuseQueue) { if (!page.superview && [page.reuseIdentifier isEqualToString:identifier]) { @@ -153,9 +145,9 @@ - (__kindof UIView *)dequeueReusablePageWithIdentifier:(NSString *)identifier { #pragma mark Properties -- (UIScrollView *)contentView { +- (MXContentView *)contentView { if (!_contentView) { - _contentView = [[UIScrollView alloc] init]; + _contentView = [[MXContentView alloc] init]; _contentView.delegate = self; _contentView.scrollsToTop = NO; _contentView.pagingEnabled = YES; @@ -329,3 +321,56 @@ - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { } @end + +@implementation MXContentView + +#pragma mark + +- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ + + if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) { + MXPanGestureDirection direction = [(UIPanGestureRecognizer*)gestureRecognizer directionInView:self]; + + //Lock vertical pan gesture. + if (direction == MXPanGestureDirectionUp || direction == MXPanGestureDirectionDown) { + return NO; + } + } + return YES; +} + +@end + +@implementation UIView (ReuseIdentifier) + +- (NSString *)reuseIdentifier { + return objc_getAssociatedObject(self, @selector(reuseIdentifier)); +} + +- (void)setReuseIdentifier:(NSString *)reuseIdentifier { + objc_setAssociatedObject(self, @selector(reuseIdentifier), reuseIdentifier, OBJC_ASSOCIATION_COPY); +} + +- (void)prepareForReuse { + +} + +@end + +@implementation UIPanGestureRecognizer (Direction) + +- (MXPanGestureDirection) directionInView:(UIView *)view { + CGPoint velocity = [self velocityInView:view]; + CGFloat absX = fabs(velocity.x); + CGFloat absY = fabs(velocity.y); + + if (absX > absY) { + return (velocity.x > 0)? MXPanGestureDirectionRight : MXPanGestureDirectionLeft; + } + else if (absX < absY) { + return (velocity.y > 0)? MXPanGestureDirectionDown : MXPanGestureDirectionUp; + } + return MXPanGestureDirectionNone; +} + +@end diff --git a/MXSegmentedPager/MXSegmentedPager.h b/MXSegmentedPager/MXSegmentedPager.h index b58f4d6f2..ffca0502d 100644 --- a/MXSegmentedPager/MXSegmentedPager.h +++ b/MXSegmentedPager/MXSegmentedPager.h @@ -187,14 +187,6 @@ typedef void (^MXProgressBlock) (CGFloat progress); */ - (void) reloadData; -/** - Scrolls through the pager until a page identified by index is at a particular location on the screen. - - @param index An index that identifies a page. - @param animated YES if you want to animate the change in position; NO if it should be immediate. - */ -- (void) scrollToPageAtIndex:(NSInteger)index animated:(BOOL)animated; - @end /** diff --git a/MXSegmentedPager/MXSegmentedPager.m b/MXSegmentedPager/MXSegmentedPager.m index 0d63b64f3..138f77f9d 100644 --- a/MXSegmentedPager/MXSegmentedPager.m +++ b/MXSegmentedPager/MXSegmentedPager.m @@ -23,13 +23,7 @@ #import #import "MXSegmentedPager.h" -typedef NS_ENUM(NSInteger, MXPanGestureDirection) { - MXPanGestureDirectionNone = 1 << 0, - MXPanGestureDirectionRight = 1 << 1, - MXPanGestureDirectionLeft = 1 << 2, - MXPanGestureDirectionUp = 1 << 3, - MXPanGestureDirectionDown = 1 << 4 -}; + @interface MXScrollView : UIScrollView @property (nonatomic, assign) CGFloat minimumHeigth; @@ -120,11 +114,9 @@ - (void)reloadData { self.segmentedControl.sectionImages = images; self.segmentedControl.sectionTitles = titles; -} - -- (void) scrollToPageAtIndex:(NSInteger)index animated:(BOOL)animated { - [self.segmentedControl setSelectedSegmentIndex:index animated:animated]; - [self.pager showPageAtIndex:index animated:animated]; + + [self.pager reloadData]; + [self layoutIfNeeded]; } #pragma mark Properties @@ -336,8 +328,9 @@ - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) { - MXPanGestureDirection direction = [self getDirectionOfPanGestureRecognizer:(UIPanGestureRecognizer*)gestureRecognizer]; + MXPanGestureDirection direction = [(UIPanGestureRecognizer*)gestureRecognizer directionInView:self]; + //Lock horizontal pan gesture. if (direction == MXPanGestureDirectionLeft || direction == MXPanGestureDirectionRight) { return NO; } @@ -348,7 +341,7 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { UIView *page = (id) self.segmentedPager.pager.selectedPage; - BOOL shouldScroll = self.scrollEnabled; + BOOL shouldScroll = YES; if ([page respondsToSelector:@selector(segmentedPager:shouldScrollWithView:)]) { shouldScroll = [page segmentedPager:self.segmentedPager shouldScrollWithView:otherGestureRecognizer.view]; @@ -360,21 +353,6 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecogni return shouldScroll; } -- (MXPanGestureDirection) getDirectionOfPanGestureRecognizer:(UIPanGestureRecognizer*) panGestureRecognizer { - - CGPoint velocity = [panGestureRecognizer velocityInView:self]; - CGFloat absX = fabs(velocity.x); - CGFloat absY = fabs(velocity.y); - - if (absX > absY) { - return (velocity.x > 0)? MXPanGestureDirectionRight : MXPanGestureDirectionLeft; - } - else if (absX < absY) { - return (velocity.y > 0)? MXPanGestureDirectionDown : MXPanGestureDirectionUp; - } - return MXPanGestureDirectionNone; -} - #pragma mark KVO - (void) addObserverToView:(UIView *)view {