Another code design change..

[NEW]: make use of the parent/child relationship to propagate the deltaY down the hierarchy!
This commit is contained in:
Mazyad Alabduljaleel 2014-06-15 15:10:36 +04:00
parent 7e10314d2f
commit e4ffe134c3
4 changed files with 83 additions and 44 deletions

View File

@ -21,6 +21,8 @@
@property (nonatomic, weak) UIScrollView *scrollView;
- (void)addExtensionView:(UIView *)view;
- (void)layoutViews;
- (void)scrollViewDidEndScrolling;
@end

View File

@ -21,7 +21,6 @@ static inline CGFloat AACStatusBarHeight()
@interface TLYShyNavBarManager () <UIGestureRecognizerDelegate>
@property (nonatomic, strong) TLYShyViewController *extensionController;
@property (nonatomic, strong) TLYShyViewController *navBarController;
@property (nonatomic, strong) UIView *extensionViewsContainer;
@ -34,6 +33,8 @@ static inline CGFloat AACStatusBarHeight()
@implementation TLYShyNavBarManager
#pragma mark - Init & Dealloc
- (instancetype)init
{
self = [super init];
@ -57,20 +58,21 @@ static inline CGFloat AACStatusBarHeight()
self.extensionViewsContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100.f, 0.f)];
self.extensionViewsContainer.backgroundColor = [UIColor clearColor];
self.extensionController = [[TLYShyViewController alloc] init];
self.extensionController.hidesAfterContraction = YES;
self.extensionController.view = self.extensionViewsContainer;
self.extensionController.contractionAmount = ^(UIView *view)
TLYShyViewController *extensionController = [[TLYShyViewController alloc] init];
extensionController.view = self.extensionViewsContainer;
extensionController.contractionAmount = ^(UIView *view)
{
return CGRectGetHeight(view.bounds);
};
__weak typeof(self) weakSelf = self;
self.extensionController.expandedCenter = ^(UIView *view)
extensionController.expandedCenter = ^(UIView *view)
{
return CGPointMake(CGRectGetMidX(view.bounds),
CGRectGetMidY(view.bounds) + weakSelf.viewController.topLayoutGuide.length);
};
self.navBarController.child = extensionController;
}
return self;
}
@ -82,13 +84,6 @@ static inline CGFloat AACStatusBarHeight()
#pragma mark - Properties
- (void)addExtensionView:(UIView *)view
{
// TODO: expand the container instead of just adding it on top
self.extensionViewsContainer.frame = view.bounds;
[self.extensionViewsContainer addSubview:view];
}
- (void)setViewController:(UIViewController *)viewController
{
_viewController = viewController;
@ -98,7 +93,7 @@ static inline CGFloat AACStatusBarHeight()
self.navBarController.view = viewController.navigationController.navigationBar;
[self _layoutViews];
[self layoutViews];
}
- (void)setScrollView:(UIScrollView *)scrollView
@ -110,17 +105,6 @@ static inline CGFloat AACStatusBarHeight()
#pragma mark - Private methods
- (void)_layoutViews
{
[self.extensionController expand];
UIEdgeInsets scrollInsets = self.scrollView.contentInset;
scrollInsets.top = CGRectGetHeight(self.extensionViewsContainer.bounds) + self.viewController.topLayoutGuide.length;
self.scrollView.contentInset = scrollInsets;
self.scrollView.scrollIndicatorInsets = scrollInsets;
}
- (void)_handleScrolling
{
if (!isnan(self.previousYOffset))
@ -145,8 +129,7 @@ static inline CGFloat AACStatusBarHeight()
self.isContracting = deltaY < 0;
}
deltaY = [(self.isContracting ? self.extensionController : self.navBarController) updateYOffset:deltaY];
[(self.isContracting ? self.navBarController : self.extensionController) updateYOffset:deltaY];
[self.navBarController updateYOffset:deltaY];
}
self.previousYOffset = self.scrollView.contentOffset.y;
@ -154,16 +137,10 @@ static inline CGFloat AACStatusBarHeight()
- (void)_handleScrollingEnded
{
TLYShyViewController *first = (self.isContracting ? self.extensionController : self.navBarController);
TLYShyViewController *second = (self.isContracting ? self.navBarController : self.extensionController);
NSTimeInterval duration = 0;
CGFloat deltaY = 0;
deltaY = [first snap:self.isContracting afterDelay:duration];
duration = fabs(deltaY/contractionVelocity);
deltaY += [second snap:self.isContracting afterDelay:duration];
deltaY = [self.navBarController snap:self.isContracting afterDelay:duration];
duration = fabs(deltaY/contractionVelocity);
CGPoint newContentOffset = self.scrollView.contentOffset;
@ -175,11 +152,33 @@ static inline CGFloat AACStatusBarHeight()
}];
}
#pragma mark - public methods
- (void)layoutViews
{
[self.navBarController expand];
UIEdgeInsets scrollInsets = self.scrollView.contentInset;
scrollInsets.top = CGRectGetHeight(self.extensionViewsContainer.bounds) + self.viewController.topLayoutGuide.length;
self.scrollView.contentInset = scrollInsets;
self.scrollView.scrollIndicatorInsets = scrollInsets;
}
- (void)addExtensionView:(UIView *)view
{
// TODO: expand the container instead of just adding it on top
self.extensionViewsContainer.frame = view.bounds;
[self.extensionViewsContainer addSubview:view];
}
- (void)scrollViewDidEndScrolling
{
[self _handleScrollingEnded];
}
#pragma mark - KVO methods
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqual:NSStringFromSelector(@selector(contentOffset))])

View File

@ -13,15 +13,28 @@ extern const CGFloat contractionVelocity;
typedef CGPoint(^TLYShyViewControllerExpandedCenterBlock)(UIView *view);
typedef CGFloat(^TLYShyViewControllerContractionAmountBlock)(UIView *view);
/* CLASS DESCRIPTION:
* ==================
* A shy view is a view that contracts when a scrolling event is
* triggered. We use this class to control the operations we perform on
* the shy view.
*
* ShyViewControllers can have a child, which gets the same offset
* updates as its parent. The use for this is to implement a drawer like
* functionality. When a parent is contracted/expanded, we want the child
* which is beneath the view to move the same amount so it remains hidden.
*/
@interface TLYShyViewController : NSObject
@property (nonatomic, strong) TLYShyViewController *child;
@property (nonatomic, weak) UIView *view;
@property (nonatomic, copy) TLYShyViewControllerExpandedCenterBlock expandedCenter;
@property (nonatomic, copy) TLYShyViewControllerContractionAmountBlock contractionAmount;
@property (nonatomic) BOOL hidesSubviews;
@property (nonatomic) BOOL hidesAfterContraction;
- (CGFloat)updateYOffset:(CGFloat)deltaY;

View File

@ -53,30 +53,42 @@ const CGFloat contractionVelocity = 140.f;
}
}
- (CGFloat)updateYOffset:(CGFloat)deltaY
- (CGFloat)_updateYOffset:(CGFloat)deltaY overrideLimit:(BOOL)override
{
if (self.child && deltaY < 0)
{
deltaY = [self.child updateYOffset:deltaY];
}
CGFloat newYOffset = self.view.center.y + deltaY;
CGFloat newYCenter = MAX(MIN(self.expandedCenterValue.y, newYOffset), self.contractedCenterValue.y);
CGFloat newYCenter = override ? newYOffset : MAX(MIN(self.expandedCenterValue.y, newYOffset), self.contractedCenterValue.y);
self.view.center = CGPointMake(self.expandedCenterValue.x, newYCenter);
CGFloat newAlpha = 1.f - (self.expandedCenterValue.y - self.view.center.y) / self.contractionAmountValue;
newAlpha = MIN(MAX(FLT_EPSILON, newAlpha), 1.f);
if (self.hidesSubviews)
{
CGFloat newAlpha = 1.f - (self.expandedCenterValue.y - self.view.center.y) / self.contractionAmountValue;
newAlpha = MIN(MAX(FLT_EPSILON, newAlpha), 1.f);
[self _updateSubviewsToAlpha:newAlpha];
}
if (self.hidesAfterContraction)
CGFloat residual = newYOffset - newYCenter;
self.child.view.center = CGPointMake(self.child.view.center.x, self.child.view.center.y + deltaY - residual);
if (self.child && deltaY > 0)
{
self.view.alpha = fabs(newYCenter - self.contractedCenterValue.y) < FLT_EPSILON ? 0.f : 1.f;
residual = [self.child updateYOffset:residual];
}
CGFloat residual = newYOffset - newYCenter;
return residual;
}
- (CGFloat)updateYOffset:(CGFloat)deltaY
{
return [self _updateYOffset:deltaY overrideLimit:NO];
}
- (CGFloat)snap:(BOOL)contract afterDelay:(NSTimeInterval)delay
{
CGFloat newYCenter = (contract
@ -84,8 +96,21 @@ const CGFloat contractionVelocity = 140.f;
: self.expandedCenterValue.y);
CGFloat deltaY = newYCenter - self.view.center.y;
CGFloat duration = fabs(deltaY/contractionVelocity);
[UIView animateWithDuration:fabs(deltaY/contractionVelocity)
if (contract)
{
CGFloat childDelta = [self.child snap:contract afterDelay:delay];
delay = fabs(childDelta/contractionVelocity);
deltaY += childDelta;
}
else
{
deltaY += [self.child snap:contract afterDelay:delay+duration];
}
[UIView animateWithDuration:duration
delay:delay
options:UIViewAnimationOptionCurveEaseInOut
animations:^{