Another code design change..
[NEW]: make use of the parent/child relationship to propagate the deltaY down the hierarchy!
This commit is contained in:
parent
7e10314d2f
commit
e4ffe134c3
|
|
@ -21,6 +21,8 @@
|
|||
@property (nonatomic, weak) UIScrollView *scrollView;
|
||||
|
||||
- (void)addExtensionView:(UIView *)view;
|
||||
|
||||
- (void)layoutViews;
|
||||
- (void)scrollViewDidEndScrolling;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -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))])
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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:^{
|
||||
|
|
|
|||
Loading…
Reference in New Issue