Skip to content

Commit

Permalink
Add MXPageDelegate for parallax header.
Browse files Browse the repository at this point in the history
Add selectedPage property to MXSegmentedPager.
  • Loading branch information
Maxime Epain committed Mar 22, 2015
1 parent d06f506 commit 8ac00b7
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 12 deletions.
34 changes: 34 additions & 0 deletions Pod/Classes/MXSegmentedPager+ParallaxHeader.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,37 @@ typedef void (^MXProgressBlock) (CGFloat progress);
height:(CGFloat)height;

@end

/**
While using MXSegmentedPager with Parallax header, your pages can adopt the MXPageDelegate protocol to have a nice effect while scrolling.
This is useful when you have a page with a scrolling subview (e.g. UIWebView).
*/
@protocol MXPageDelegate <NSObject>

@optional

/**
Tells if the view is at its scrolling top.
@return Whether or nor the view is at its scroll top.
*/
- (BOOL) isAtTop;

/**
Scrolls to top with no animation.
*/
- (void) scrollToTop;

@end

/**
UIScrollView category that adopt the MXPageDelegate protocol.
*/
@interface UIScrollView (MXSegmentedPager) <MXPageDelegate>
@end

/**
UIWebView category that adopt the MXPageDelegate protocol.
*/
@interface UIWebView (MXSegmentedPager) <MXPageDelegate>
@end
101 changes: 89 additions & 12 deletions Pod/Classes/MXSegmentedPager+ParallaxHeader.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,15 @@ @interface MXScrollView : UIScrollView <UIScrollViewDelegate, UIGestureRecognize
@property (nonatomic, assign) CGFloat minimumHeigth;
@property (nonatomic, strong) MXSegmentedPager *segmentedPager;
@property (nonatomic, strong) MXProgressBlock progressBlock;

@property (nonatomic, assign) BOOL moveView;
@end

@implementation MXScrollView

static void * const kMXScrollViewKVOContext = (void*)&kMXScrollViewKVOContext;
static NSString* const kContentOffsetKeyPath = @"contentOffset";

- (void)setSegmentedPager:(MXSegmentedPager*)segmentedPager {
_segmentedPager = segmentedPager;
[self addSubview:segmentedPager.segmentedControl];
Expand All @@ -56,6 +61,9 @@ - (instancetype)initWithFrame:(CGRect)frame {
self.directionalLockEnabled = YES;

self.minimumHeigth = 0;

[self addObserver:self forKeyPath:kContentOffsetKeyPath options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:kMXScrollViewKVOContext];
self.moveView = YES;
}
return self;
}
Expand All @@ -69,10 +77,6 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView
if (self.progressBlock) {
self.progressBlock(scrollView.parallaxHeader.progress);
}

if (self.contentOffset.y > -self.minimumHeigth) {
self.contentOffset = CGPointMake(self.contentOffset.x, -self.minimumHeigth);
}
}

#pragma mark <UIGestureRecognizerDelegate>
Expand All @@ -89,7 +93,7 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
return YES;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}

Expand All @@ -110,6 +114,52 @@ - (MXPanGestureDirection) getDirectionOfPanGestureRecognizer:(UIPanGestureRecogn
return MXPanGestureDirectionNone;
}

- (void) didScrollWithDelta:(CGFloat)delta {

self.moveView = NO;
// [self removeObserver:self forKeyPath:kContentOffsetKeyPath context:kMXScrollViewKVOContext];

UIView<MXPageDelegate>* page = (id) self.segmentedPager.selectedPage;

if (page) {

BOOL isAtTop = ([page respondsToSelector:@selector(isAtTop)])? [page isAtTop] : YES;

if (self.contentOffset.y > -self.minimumHeigth) {
self.contentOffset = CGPointMake(self.contentOffset.x, -self.minimumHeigth);
}
else if (self.contentOffset.y + delta >= -self.minimumHeigth && !isAtTop) {
self.contentOffset = CGPointMake(self.contentOffset.x, -self.minimumHeigth);
}

if (self.contentOffset.y < -self.minimumHeigth && [page respondsToSelector:@selector(scrollToTop)]) {
[page scrollToTop];
}
}

self.moveView = YES;
// [self addObserver:self forKeyPath:kContentOffsetKeyPath options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:kMXScrollViewKVOContext];
}

#pragma mark KVO

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

if (context == kMXScrollViewKVOContext && [keyPath isEqualToString:kContentOffsetKeyPath]) {

if (self.moveView) {
CGPoint newOffset = [[change objectForKey:NSKeyValueChangeNewKey] CGPointValue];
CGPoint oldOffset = [[change objectForKey:NSKeyValueChangeOldKey] CGPointValue];
CGFloat delta = oldOffset.y - newOffset.y;

[self didScrollWithDelta:delta];
}
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

@end

@interface MXSegmentedPager ()
Expand All @@ -118,7 +168,8 @@ @interface MXSegmentedPager ()

@implementation MXSegmentedPager (ParallaxHeader)

static NSString* const kContaineFrameKeyPath = @"container.frame";
static void * const kMXSegmentedPagerKVOContext = (void*)&kMXSegmentedPagerKVOContext;
static NSString* const kFrameKeyPath = @"frame";

- (void)setParallaxHeaderView:(UIView *)view mode:(VGParallaxHeaderMode)mode height:(CGFloat)height {

Expand All @@ -132,8 +183,7 @@ - (void)setParallaxHeaderView:(UIView *)view mode:(VGParallaxHeaderMode)mode hei
[self.scrollView setParallaxHeaderView:view mode:mode height:height];
[self addSubview:self.scrollView];

//I'm not a big fan of KVO but its the only way I found to subtract minimum height to container frame.
[self addObserver:self forKeyPath:kContaineFrameKeyPath options:NSKeyValueObservingOptionNew context:nil];
[self.container addObserver:self forKeyPath:kFrameKeyPath options:NSKeyValueObservingOptionNew context:kMXSegmentedPagerKVOContext];
}

#pragma mark Properties
Expand Down Expand Up @@ -169,20 +219,47 @@ - (void)setProgressBlock:(MXProgressBlock)progressBlock {
#pragma mark KVO

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (object == self && [keyPath isEqualToString:kContaineFrameKeyPath]) {
[self removeObserver:self forKeyPath:kContaineFrameKeyPath];
if (context == kMXSegmentedPagerKVOContext && [keyPath isEqualToString:kFrameKeyPath]) {
[self.container removeObserver:self forKeyPath:kFrameKeyPath context:kMXSegmentedPagerKVOContext];

self.container.frame = (CGRect){
.origin = self.container.frame.origin,
.size.width = self.container.frame.size.width,
.size.height = self.container.frame.size.height - self.scrollView.minimumHeigth
};

[self addObserver:self forKeyPath:kContaineFrameKeyPath options:NSKeyValueObservingOptionNew context:nil];
[self.container addObserver:self forKeyPath:kFrameKeyPath options:NSKeyValueObservingOptionNew context:kMXSegmentedPagerKVOContext];
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:nil];
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

@end

@implementation UIScrollView (MXSegmentedPager)

#pragma mark <MXPageDelegate>

- (BOOL) isAtTop {
return (self.contentOffset.y <= -self.contentInset.top);
}

- (void) scrollToTop {
self.contentOffset = CGPointMake(self.contentOffset.x, -self.contentInset.top);
}

@end

@implementation UIWebView (MXSegmentedPager)

#pragma mark <MXPageDelegate>

- (BOOL) isAtTop {
return (self.scrollView.contentOffset.y <= self.scrollView.contentInset.top);
}

- (void) scrollToTop {
self.scrollView.contentOffset = CGPointMake(self.scrollView.contentOffset.x, -self.scrollView.contentInset.top);
}
@end
5 changes: 5 additions & 0 deletions Pod/Classes/MXSegmentedPager.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@
*/
@property (nonatomic, assign) CGSize containerSize;

/**
The current selected page view.
*/
@property (nonatomic, readonly) UIView* selectedPage;

/**
Reloads everything from scratch. redisplays pages in container.
*/
Expand Down
8 changes: 8 additions & 0 deletions Pod/Classes/MXSegmentedPager.m
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ - (void)setContainerSize:(CGSize)containerSize {
};
}

- (UIView*) selectedPage {
NSInteger index = self.segmentedControl.selectedSegmentIndex;
if (self.pages.count > index) {
return [self.pages objectAtIndex:index];
}
return nil;
}

#pragma mark HMSegmentedControl target

- (void)pageControlValueChanged:(HMSegmentedControl*)segmentedControl {
Expand Down

0 comments on commit 8ac00b7

Please sign in to comment.