From 6ad3b1d7a0cccf6bc0bc930dcf2ea21d878ab9e4 Mon Sep 17 00:00:00 2001 From: Mazyad Alabduljaleel Date: Fri, 13 Jun 2014 18:36:58 +0300 Subject: [PATCH] Major overhaul [NEW]: move to component based design. [NEW]: implemented most of the things. [DAMN]: couldn't find a way to track scrollview's dragging state --- TLYShyNavBar/TLYShyNavBarController.h | 32 +++ TLYShyNavBar/TLYShyNavBarController.m | 224 ++++++++++++++++++ TLYShyNavBar/UIViewController+ShyNavBar.h | 17 -- TLYShyNavBar/UIViewController+ShyNavBar.m | 188 --------------- .../project.pbxproj | 12 +- .../TLYShyNavBarDemo-Prefix.pch | 2 +- .../TLYShyNavBarDemo/TLYViewController.m | 54 ++++- 7 files changed, 304 insertions(+), 225 deletions(-) create mode 100644 TLYShyNavBar/TLYShyNavBarController.h create mode 100644 TLYShyNavBar/TLYShyNavBarController.m delete mode 100644 TLYShyNavBar/UIViewController+ShyNavBar.h delete mode 100644 TLYShyNavBar/UIViewController+ShyNavBar.m diff --git a/TLYShyNavBar/TLYShyNavBarController.h b/TLYShyNavBar/TLYShyNavBarController.h new file mode 100644 index 0000000..a721458 --- /dev/null +++ b/TLYShyNavBar/TLYShyNavBarController.h @@ -0,0 +1,32 @@ +// +// TLYShyNavBarController.h +// TLYShyNavBarDemo +// +// Created by Mazyad Alabduljaleel on 6/13/14. +// Copyright (c) 2014 Telly, Inc. All rights reserved. +// + +#import + +/* CLASS DESCRIPTION: + * ================== + * Manages the relationship between a scrollView and a navigation + * controller. + */ + +@interface TLYShyNavBarController : NSObject + +@property (nonatomic, readonly) UIViewController *viewController; + +@property (nonatomic, weak) UIScrollView *scrollView; +@property (nonatomic, strong) UIView *extensionView; + +- (void)scrollViewDidEndScrolling; + +@end + +@interface UIViewController (ShyNavBar) + +@property (nonatomic, strong) TLYShyNavBarController *shyNavBarController; + +@end diff --git a/TLYShyNavBar/TLYShyNavBarController.m b/TLYShyNavBar/TLYShyNavBarController.m new file mode 100644 index 0000000..3488ffb --- /dev/null +++ b/TLYShyNavBar/TLYShyNavBarController.m @@ -0,0 +1,224 @@ +// +// TLYShyNavBarController.m +// TLYShyNavBarDemo +// +// Created by Mazyad Alabduljaleel on 6/13/14. +// Copyright (c) 2014 Telly, Inc. All rights reserved. +// + +#import "TLYShyNavBarController.h" +#import + +// Thanks to SO user, MattDiPasquale +// http://stackoverflow.com/questions/12991935/how-to-programmatically-get-ios-status-bar-height/16598350#16598350 + +static inline CGFloat AACStatusBarHeight() +{ + CGSize statusBarSize = [UIApplication sharedApplication].statusBarFrame.size; + return MIN(statusBarSize.width, statusBarSize.height); +} + + +@interface TLYShyNavBarController () + +@property (nonatomic, readonly) UINavigationBar *navBar; + +/* BAD: This is a cached value. Test when there is an active call, and try to compute this */ +@property (nonatomic) CGPoint initialNavBarCenter; +@property (nonatomic) CGFloat previousYOffset; + +@property (nonatomic, getter = isContracting) BOOL contracting; + +@end + +@implementation TLYShyNavBarController + +- (instancetype)init +{ + self = [super init]; + if (self) + { + self.previousYOffset = NAN; + } + return self; +} + +- (void)dealloc +{ + [_scrollView removeObserver:self forKeyPath:@"contentOffset"]; +} + +#pragma mark - Properties + +- (void)setExtensionView:(UIView *)extensionView +{ + if (_extensionView.superview == self.viewController.navigationController.view) + { + [_extensionView removeFromSuperview]; + } + + _extensionView = extensionView; + + CGRect frame = extensionView.frame; + frame.origin.y = CGRectGetMaxY(self.navBar.frame); + + extensionView.frame = frame; + + [self.viewController.navigationController.view addSubview:extensionView]; +} + + +- (void)setViewController:(UIViewController *)viewController +{ + _viewController = viewController; + + self.initialNavBarCenter = self.navBar.center; +} + +- (void)setScrollView:(UIScrollView *)scrollView +{ + [_scrollView removeObserver:self forKeyPath:@"contentOffset"]; + _scrollView = scrollView; + [_scrollView addObserver:self forKeyPath:@"contentOffset" options:0 context:NULL]; +} + +- (UINavigationBar *)navBar +{ + return self.viewController.navigationController.navigationBar; +} + +#pragma mark - Private methods + +- (CGFloat)_contractionAmount +{ + return CGRectGetHeight(self.navBar.bounds); +} + +- (CGFloat)_updateNavigationBarToState:(BOOL)contract +{ + static const CGFloat velocity = 140.f; + + CGFloat newCenterY = (contract + ? self.initialNavBarCenter.y - [self _contractionAmount] + : self.initialNavBarCenter.y); + + CGFloat deltaY = newCenterY - self.navBar.center.y; + + [UIView animateWithDuration:fabs(deltaY/velocity) + animations:^{ + self.navBar.center = CGPointMake(self.navBar.center.x, newCenterY); + [self _updateSubviewsAlpha:self.isContracting ? FLT_EPSILON : 1.f]; + }]; + + return deltaY; +} + +- (void)_updateNavigationBarWithDeltaY:(CGFloat)deltaY +{ + CGPoint newCenter = self.navBar.center; + newCenter.y = MAX(MIN(self.initialNavBarCenter.y, newCenter.y - deltaY), + self.initialNavBarCenter.y - [self _contractionAmount]); + + self.navBar.center = newCenter; + + CGFloat newAlpha = 1.f - (self.initialNavBarCenter.y - newCenter.y) / [self _contractionAmount]; + newAlpha = MIN(MAX(FLT_EPSILON, newAlpha), 1.f); + + NSMutableArray *navItems = [NSMutableArray array]; + [navItems addObjectsFromArray:self.viewController.navigationItem.leftBarButtonItems]; + [navItems addObjectsFromArray:self.viewController.navigationItem.rightBarButtonItems]; + + if (self.navBar.topItem.titleView) + { + [navItems addObject:self.navBar.topItem.titleView]; + } + + [self _updateSubviewsAlpha:newAlpha]; + + self.contracting = deltaY > 0; +} + +- (void)_updateSubviewsAlpha:(CGFloat)alpha +{ + for (UIView* view in self.navBar.subviews) + { + bool isBackgroundView = view == self.navBar.subviews[0]; + bool isViewHidden = view.hidden || view.alpha < FLT_EPSILON; + + if (isBackgroundView || isViewHidden) + continue; + + view.alpha = alpha; + } +} + +- (void)_handleScrolling +{ + if (!isnan(self.previousYOffset)) + { + CGFloat deltaY = (self.scrollView.contentOffset.y - self.previousYOffset); + CGFloat offset; + + offset = -self.scrollView.contentInset.top; + if (self.scrollView.contentOffset.y - deltaY < offset) + { + deltaY = MAX(0, self.scrollView.contentOffset.y - deltaY + offset); + } + + /* rounding to resolve a dumb issue with the contentOffset value */ + offset = floorf(self.scrollView.contentSize.height - CGRectGetHeight(self.scrollView.bounds) - self.scrollView.contentInset.bottom - 0.5f); + if (self.scrollView.contentOffset.y + deltaY > offset) + { + deltaY = MAX(0, self.scrollView.contentOffset.y + deltaY + offset); + } + + [self _updateNavigationBarWithDeltaY:deltaY]; + } + + self.previousYOffset = self.scrollView.contentOffset.y; +} + +- (void)_handleScrollingEnded +{ + CGFloat deltaY = [self _updateNavigationBarToState:self.isContracting]; + + CGPoint newContentOffset = self.scrollView.contentOffset; + newContentOffset.y -= deltaY; + + // TODO: manually animate content offset to match navbar animation + [self.scrollView setContentOffset:newContentOffset animated:YES]; +} + +- (void)scrollViewDidEndScrolling +{ + [self _handleScrollingEnded]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([keyPath isEqual:NSStringFromSelector(@selector(contentOffset))]) + { + [self _handleScrolling]; + } +} + +@end + + +static char shyNavBarControllerKey; + +@implementation UIViewController (ShyNavBar) + +- (void)setShyNavBarController:(TLYShyNavBarController *)shyNavBarController +{ + shyNavBarController.viewController = self; + objc_setAssociatedObject(self, ­NavBarControllerKey, shyNavBarController, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (TLYShyNavBarController *)shyNavBarController +{ + return objc_getAssociatedObject(self, ­NavBarControllerKey); +} + +@end + diff --git a/TLYShyNavBar/UIViewController+ShyNavBar.h b/TLYShyNavBar/UIViewController+ShyNavBar.h deleted file mode 100644 index 6ce38cd..0000000 --- a/TLYShyNavBar/UIViewController+ShyNavBar.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// UIViewController+ShyNavBar.h -// TLYShyNavBarDemo -// -// Created by Mazyad Alabduljaleel on 6/12/14. -// Copyright (c) 2014 Telly, Inc. All rights reserved. -// - -#import - -@interface UIViewController (ShyNavBar) - -- (void)tly_scrollViewWillBeginDragging:(UIScrollView *)scrollView; -- (void)tly_scrollViewDidScroll:(UIScrollView *)scrollView; -- (void)tly_scrollViewDidEndDragging:(UIScrollView *)scrollView; - -@end diff --git a/TLYShyNavBar/UIViewController+ShyNavBar.m b/TLYShyNavBar/UIViewController+ShyNavBar.m deleted file mode 100644 index af64146..0000000 --- a/TLYShyNavBar/UIViewController+ShyNavBar.m +++ /dev/null @@ -1,188 +0,0 @@ -// -// UIViewController+ShyNavBar.m -// TLYShyNavBarDemo -// -// Created by Mazyad Alabduljaleel on 6/12/14. -// Copyright (c) 2014 Telly, Inc. All rights reserved. -// - -#import "UIViewController+ShyNavBar.h" -#import "TLYViewController.h" -#import - -static char initialNavBarCenterKey; -static char previousYOffsetKey; -static char draggingKey; -static char contractingKey; - -static const CGFloat contractionAmount = 44.f; - -@interface UIViewController () - -@property (nonatomic, readonly) UINavigationBar *navBar; - -@property (nonatomic) CGPoint initialNavBarCenter; -@property (nonatomic) CGFloat previousYOffset; - -@property (nonatomic, getter = isDragging) BOOL dragging; -@property (nonatomic, getter = isContracting) BOOL contracting; - -@end - -@implementation UIViewController (ShyNavBar) - -#pragma mark - Category properties - -- (UINavigationBar *)navBar -{ - return self.navigationController.navigationBar; -} - -- (void)setInitialNavBarCenter:(CGPoint)initialNavBarCenter -{ - objc_setAssociatedObject(self, &initialNavBarCenterKey, [NSValue valueWithCGPoint:initialNavBarCenter], OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (CGPoint)initialNavBarCenter -{ - id value = objc_getAssociatedObject(self, &initialNavBarCenterKey); - CGPoint center = [value CGPointValue]; - if (!value) - { - center = self.navigationController.navigationBar.center; - self.initialNavBarCenter = center; - } - - return center; -} - -- (void)setPreviousYOffset:(CGFloat)previousYOffset -{ - objc_setAssociatedObject(self, &previousYOffsetKey, @(previousYOffset), OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (CGFloat)previousYOffset -{ - id number = objc_getAssociatedObject(self, &previousYOffsetKey); - return number ? [number floatValue] : NAN; -} - -- (void)setDragging:(BOOL)dragging -{ - objc_setAssociatedObject(self, &draggingKey, @(dragging), OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (BOOL)isDragging -{ - return [objc_getAssociatedObject(self, &draggingKey) boolValue]; -} - -- (void)setContracting:(BOOL)contracting -{ - objc_setAssociatedObject(self, &contractingKey, @(contracting), OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (BOOL)isContracting -{ - return [objc_getAssociatedObject(self, &contractingKey) boolValue]; -} - -#pragma mark - Private methods - -- (void)_updateNavigationBarWithDeltaY:(CGFloat)deltaY -{ - CGPoint newCenter = self.navBar.center; - newCenter.y = MAX(MIN(self.initialNavBarCenter.y, newCenter.y - deltaY), - self.initialNavBarCenter.y - contractionAmount); - - self.navBar.center = newCenter; - - CGFloat newAlpha = 1.f - (self.initialNavBarCenter.y - newCenter.y) / contractionAmount; - newAlpha = MIN(MAX(FLT_EPSILON, newAlpha), 1.f); - - NSMutableArray *navItems = [NSMutableArray array]; - [navItems addObjectsFromArray:self.navigationItem.leftBarButtonItems]; - [navItems addObjectsFromArray:self.navigationItem.rightBarButtonItems]; - - if (self.navBar.topItem.titleView) - { - [navItems addObject:self.navBar.topItem.titleView]; - } - - [self _updateSubviewsAlpha:newAlpha]; - - self.contracting = deltaY > 0; -} - -- (void)_updateSubviewsAlpha:(CGFloat)alpha -{ - for (UIView* view in self.navBar.subviews) - { - bool isBackgroundView = view == self.navBar.subviews[0]; - bool isViewHidden = view.hidden || view.alpha < FLT_EPSILON; - - if (isBackgroundView || isViewHidden) - continue; - - view.alpha = alpha; - } -} - -#pragma mark - Public methods - -- (void)tly_scrollViewWillBeginDragging:(UIScrollView *)scrollView -{ - self.dragging = YES; -} - -- (void)tly_scrollViewDidScroll:(UIScrollView *)scrollView -{ - if (!isnan(self.previousYOffset)) - { - CGFloat deltaY = scrollView.contentOffset.y - self.previousYOffset; - CGFloat offset; - - offset = -scrollView.contentInset.top; - if (scrollView.contentOffset.y - deltaY < offset) - { - deltaY = MAX(0, scrollView.contentOffset.y - deltaY + offset); - } - - offset = scrollView.contentSize.height - CGRectGetHeight(scrollView.bounds) - scrollView.contentInset.bottom; - if (scrollView.contentOffset.y + deltaY > offset) - { - deltaY = MAX(0, scrollView.contentOffset.y + deltaY + offset); - } - - [self _updateNavigationBarWithDeltaY:deltaY]; - } - - self.previousYOffset = scrollView.contentOffset.y; -} - -- (void)tly_scrollViewDidEndDragging:(UIScrollView *)scrollView -{ - static const CGFloat velocity = 140.f; - - self.dragging = NO; - - CGFloat newCenterY = (self.isContracting - ? self.initialNavBarCenter.y - contractionAmount - : self.initialNavBarCenter.y); - - CGFloat deltaY = newCenterY - self.navBar.center.y; - - [UIView animateWithDuration:fabs(deltaY/velocity) - animations:^{ - self.navBar.center = CGPointMake(self.navBar.center.x, newCenterY); - [self _updateSubviewsAlpha:self.isContracting ? FLT_EPSILON : 1.f]; - }]; - - CGPoint newContentOffset = scrollView.contentOffset; - newContentOffset.y -= deltaY; - - // TODO: manually animate content offset to match navbar animation - [scrollView setContentOffset:newContentOffset animated:YES]; -} - -@end diff --git a/TLYShyNavBarDemo/TLYShyNavBarDemo.xcodeproj/project.pbxproj b/TLYShyNavBarDemo/TLYShyNavBarDemo.xcodeproj/project.pbxproj index 40a374a..fbb19b3 100644 --- a/TLYShyNavBarDemo/TLYShyNavBarDemo.xcodeproj/project.pbxproj +++ b/TLYShyNavBarDemo/TLYShyNavBarDemo.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 8268F9F01949CC9D004EC0E4 /* UIViewController+ShyNavBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 8268F9EF1949CC9D004EC0E4 /* UIViewController+ShyNavBar.m */; }; + 8268F9FF194AE04B004EC0E4 /* TLYShyNavBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8268F9FE194AE04B004EC0E4 /* TLYShyNavBarController.m */; }; 828F57201949C37B009EB8DD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 828F571F1949C37B009EB8DD /* Foundation.framework */; }; 828F57221949C37B009EB8DD /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 828F57211949C37B009EB8DD /* CoreGraphics.framework */; }; 828F57241949C37B009EB8DD /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 828F57231949C37B009EB8DD /* UIKit.framework */; }; @@ -35,8 +35,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 8268F9EE1949CC9D004EC0E4 /* UIViewController+ShyNavBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+ShyNavBar.h"; sourceTree = ""; }; - 8268F9EF1949CC9D004EC0E4 /* UIViewController+ShyNavBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+ShyNavBar.m"; sourceTree = ""; }; + 8268F9FD194AE04B004EC0E4 /* TLYShyNavBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TLYShyNavBarController.h; sourceTree = ""; }; + 8268F9FE194AE04B004EC0E4 /* TLYShyNavBarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TLYShyNavBarController.m; sourceTree = ""; }; 828F571C1949C37B009EB8DD /* TLYShyNavBarDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TLYShyNavBarDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 828F571F1949C37B009EB8DD /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 828F57211949C37B009EB8DD /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; @@ -159,8 +159,8 @@ 828F57541949C381009EB8DD /* TLYShyNavBar */ = { isa = PBXGroup; children = ( - 8268F9EE1949CC9D004EC0E4 /* UIViewController+ShyNavBar.h */, - 8268F9EF1949CC9D004EC0E4 /* UIViewController+ShyNavBar.m */, + 8268F9FD194AE04B004EC0E4 /* TLYShyNavBarController.h */, + 8268F9FE194AE04B004EC0E4 /* TLYShyNavBarController.m */, ); name = TLYShyNavBar; path = ../TLYShyNavBar; @@ -265,8 +265,8 @@ buildActionMask = 2147483647; files = ( 828F57301949C37B009EB8DD /* TLYAppDelegate.m in Sources */, - 8268F9F01949CC9D004EC0E4 /* UIViewController+ShyNavBar.m in Sources */, 828F57361949C37B009EB8DD /* TLYViewController.m in Sources */, + 8268F9FF194AE04B004EC0E4 /* TLYShyNavBarController.m in Sources */, 828F572C1949C37B009EB8DD /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/TLYShyNavBarDemo/TLYShyNavBarDemo/TLYShyNavBarDemo-Prefix.pch b/TLYShyNavBarDemo/TLYShyNavBarDemo/TLYShyNavBarDemo-Prefix.pch index a4e00ed..b52d984 100644 --- a/TLYShyNavBarDemo/TLYShyNavBarDemo/TLYShyNavBarDemo-Prefix.pch +++ b/TLYShyNavBarDemo/TLYShyNavBarDemo/TLYShyNavBarDemo-Prefix.pch @@ -14,5 +14,5 @@ #import #import - #import "UIViewController+ShyNavBar.h" + #import "TLYShyNavBarController.h" #endif diff --git a/TLYShyNavBarDemo/TLYShyNavBarDemo/TLYViewController.m b/TLYShyNavBarDemo/TLYShyNavBarDemo/TLYViewController.m index f111d9c..50f708d 100644 --- a/TLYShyNavBarDemo/TLYShyNavBarDemo/TLYViewController.m +++ b/TLYShyNavBarDemo/TLYShyNavBarDemo/TLYViewController.m @@ -8,6 +8,24 @@ #import "TLYViewController.h" +@interface UIBarButtonItem (Telly) + ++ (UIBarButtonItem *)tly_flexibleSpaceButtonItem; + +@end + +@implementation UIBarButtonItem (Telly) + ++ (UIBarButtonItem *)tly_flexibleSpaceButtonItem +{ + return [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace + target:nil + action:nil]; +} + +@end + + @interface TLYViewController () @property (weak, nonatomic) IBOutlet UIScrollView *scrollView; @@ -22,7 +40,6 @@ self = [super initWithCoder:aDecoder]; if (self) { self.title = @"WTFox Say"; - self.toolbarItems = @[[[UIBarButtonItem alloc] initWithCustomView:[[UISegmentedControl alloc] initWithItems:@[@"One", @"Two"]]]]; } return self; } @@ -31,7 +48,20 @@ { [super viewDidLoad]; - self.navigationController.toolbarHidden = NO; + UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 44.f)]; + toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleBottomMargin; + toolbar.barTintColor = [UIColor whiteColor]; + toolbar.items = @[[UIBarButtonItem tly_flexibleSpaceButtonItem], + [[UIBarButtonItem alloc] initWithTitle:@"One" style:UIBarButtonItemStyleBordered target:nil action:nil], + [UIBarButtonItem tly_flexibleSpaceButtonItem], + [[UIBarButtonItem alloc] initWithTitle:@"Two" style:UIBarButtonItemStyleBordered target:nil action:nil], + [UIBarButtonItem tly_flexibleSpaceButtonItem]]; + + TLYShyNavBarController *shyController = [TLYShyNavBarController new]; + shyController.scrollView = self.scrollView; + shyController.extensionView = toolbar; + + self.shyNavBarController = shyController; } - (void)viewDidLayoutSubviews @@ -43,19 +73,17 @@ #pragma mark - UIScrollViewDelegate methods -- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView -{ - [self tly_scrollViewWillBeginDragging:scrollView]; -} - -- (void)scrollViewDidScroll:(UIScrollView *)scrollView -{ - [self tly_scrollViewDidScroll:scrollView]; -} - - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { - [self tly_scrollViewDidEndDragging:scrollView]; + if (!decelerate) + { + [self.shyNavBarController scrollViewDidEndScrolling]; + } +} + +- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView +{ + [self.shyNavBarController scrollViewDidEndScrolling]; } @end