https://stackoverflow.com/a/20720359/294884
If you\'re working on this problem, GTScrollNavigationBa
I used the next code to hide tabBar like in safari app. Maybe you or other people can use it with toolBar.
static CGFloat navBarOriginY = 20.0;
Create constant for base value of navigation bar origin Y position
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationController.hidesBarsOnSwipe = true;
[self.navigationController.barHideOnSwipeGestureRecognizer addTarget:self action:@selector(swipe:)];
}
Add your custom selector to handle system swipe gesture that will fire before navBar become hidden and during hiding
- (void)swipe:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled || recognizer.state == UIGestureRecognizerStateFailed) {
//If gesture state ended/canceled or failed you need entirely change frame of tabBar
CGRect finalFrame = self.tabBarController.tabBar.frame;
if (self.navigationController.navigationBar.frame.origin.y < 0) {
//Tab bar will be hidden
finalFrame.origin.y = self.maxTabBarY;
} else {
//Tab bar will be visible
finalFrame.origin.y = self.minTabBarY;
}
[self setFrameForTabBar:finalFrame animationDuration:0.3];
} else if (recognizer.state == UIGestureRecognizerStateChanged) {
//If state == changed than you need to pan your tabBar with navBar like in safari app.
CGRect frame = self.tabBarController.tabBar.frame;
CGFloat delta = navBarOriginY - self.navigationController.navigationBar.layer.presentationLayer.frame.origin.y;
frame.origin.y = self.minTabBarY + delta;
[self setFrameForTabBar:frame animationDuration:0.0];
} } }
- (void)setFrameForTabBar:(CGRect)frame animationDuration:(CGFloat)duration {
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
self.tabBarController.tabBar.frame = frame;
} completion:^(BOOL finished) {}];
});
There is no open-source that does this, but I don't see it as that difficult to implement. It may be somewhat more difficult to have the exact 1:1 behavior as Safari, but it can still be done.
MobileSafar can be attached to in the debugger and, using breakpoints and the Objective C runtime, debugged and reverse engineered.
For example, your two assumptions that no toolbar and navigation bars are used are incorrect.
Here is the view hierarchy before scrolling:
http://pastebin.com/aRXr7b5Z
And after scrolling:
http://pastebin.com/CasBNuxq
As you can see, the bars have been moved from their normal location.
Breaking on -[BrowserToolbar setFrame:]
, here is the stack trace:
* thread #1: tid = 0x2332c, 0x000000010003fa70 MobileSafari`___lldb_unnamed_function1519$$MobileSafari, queue = 'com.apple.main-thread', stop reason = breakpoint 8.1
* frame #0: 0x000000010003fa70 MobileSafari`___lldb_unnamed_function1519$$MobileSafari
frame #1: 0x0000000100023e51 MobileSafari`___lldb_unnamed_function825$$MobileSafari + 1338
frame #2: 0x00000001000268da MobileSafari`___lldb_unnamed_function871$$MobileSafari + 55
frame #3: 0x000000010009856a MobileSafari`___lldb_unnamed_function3864$$MobileSafari + 388
frame #4: 0x0000000100098996 MobileSafari`___lldb_unnamed_function3871$$MobileSafari + 154
frame #5: 0x000000010002ba89 MobileSafari`___lldb_unnamed_function990$$MobileSafari + 209
frame #6: 0x0000000102396a8c UIKit`-[UIScrollView(UIScrollViewInternal) _notifyDidScroll] + 55
frame #7: 0x000000010238692b UIKit`-[UIScrollView setContentOffset:] + 628
frame #8: 0x000000010238ab00 UIKit`-[UIScrollView _updatePanGesture] + 1989
frame #9: 0x0000000102644002 UIKit`_UIGestureRecognizerSendActions + 188
frame #10: 0x0000000102642f68 UIKit`-[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 357
frame #11: 0x0000000102647319 UIKit`___UIGestureRecognizerUpdate_block_invoke + 53
frame #12: 0x00000001026472a1 UIKit`_UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 257
frame #13: 0x000000010263f377 UIKit`_UIGestureRecognizerUpdate + 93
frame #14: 0x0000000102353e55 UIKit`-[UIWindow _sendGesturesForEvent:] + 928
frame #15: 0x0000000102354b14 UIKit`-[UIWindow sendEvent:] + 909
frame #16: 0x000000010232c6da UIKit`-[UIApplication sendEvent:] + 211
frame #17: 0x0000000102319f2d UIKit`_UIApplicationHandleEventQueue + 9579
frame #18: 0x0000000100573f21 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
frame #19: 0x00000001005737f2 CoreFoundation`__CFRunLoopDoSources0 + 242
frame #20: 0x000000010058f66f CoreFoundation`__CFRunLoopRun + 767
frame #21: 0x000000010058ef83 CoreFoundation`CFRunLoopRunSpecific + 467
frame #22: 0x00000001011a0f04 GraphicsServices`GSEventRunModal + 161
frame #23: 0x000000010231c273 UIKit`UIApplicationMain + 1010
frame #24: 0x00000001000518d2 MobileSafari`___lldb_unnamed_function1998$$MobileSafari + 1558
So it all happens after a notification of scrolling.
I put a breakpoint on MobileSafari'___lldb_unnamed_function990$$MobileSafari
and to get the self
variable, print po $arg1
. This is where all the magic happens:
http://pastebin.com/kjAXKKTW
If you are really interested in 1:1 replication, you can put breakpoints on these methods and investigate. Good luck!
I just pulled a request to GTScrollNavigationBar that helps getting the right "match finger movement". The trick is just to adjust ContentInsets according to scrollbar's frame.
It's probably not yet perfect, but it does what you look for: https://github.com/luugiathuy/GTScrollNavigationBar/pull/21