您如何自己实现此行为?我知道以下解决方案,但它会立即消失,并且与用户滚动手势的速度没有关系。
[navigationController setNavigationBarHidden: YES animated:YES];
希望这不是重复的内容,因为我不确定如何最好地描述“扩展/收缩”的行为。
[navigationController setNavigationBarHidden: YES animated:YES];
希望这不是重复的内容,因为我不确定如何最好地描述“扩展/收缩”的行为。
首先,您需要以下属性:
@property (nonatomic) CGFloat previousScrollViewYOffset;
这里是 UIScrollViewDelegate
方法:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGRect frame = self.navigationController.navigationBar.frame;
CGFloat size = frame.size.height - 21;
CGFloat framePercentageHidden = ((20 - frame.origin.y) / (frame.size.height - 1));
CGFloat scrollOffset = scrollView.contentOffset.y;
CGFloat scrollDiff = scrollOffset - self.previousScrollViewYOffset;
CGFloat scrollHeight = scrollView.frame.size.height;
CGFloat scrollContentSizeHeight = scrollView.contentSize.height + scrollView.contentInset.bottom;
if (scrollOffset <= -scrollView.contentInset.top) {
frame.origin.y = 20;
} else if ((scrollOffset + scrollHeight) >= scrollContentSizeHeight) {
frame.origin.y = -size;
} else {
frame.origin.y = MIN(20, MAX(-size, frame.origin.y - scrollDiff));
}
[self.navigationController.navigationBar setFrame:frame];
[self updateBarButtonItems:(1 - framePercentageHidden)];
self.previousScrollViewYOffset = scrollOffset;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self stoppedScrolling];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView
willDecelerate:(BOOL)decelerate
{
if (!decelerate) {
[self stoppedScrolling];
}
}
你还需要以下这些辅助方法:
- (void)stoppedScrolling
{
CGRect frame = self.navigationController.navigationBar.frame;
if (frame.origin.y < 20) {
[self animateNavBarTo:-(frame.size.height - 21)];
}
}
- (void)updateBarButtonItems:(CGFloat)alpha
{
[self.navigationItem.leftBarButtonItems enumerateObjectsUsingBlock:^(UIBarButtonItem* item, NSUInteger i, BOOL *stop) {
item.customView.alpha = alpha;
}];
[self.navigationItem.rightBarButtonItems enumerateObjectsUsingBlock:^(UIBarButtonItem* item, NSUInteger i, BOOL *stop) {
item.customView.alpha = alpha;
}];
self.navigationItem.titleView.alpha = alpha;
self.navigationController.navigationBar.tintColor = [self.navigationController.navigationBar.tintColor colorWithAlphaComponent:alpha];
}
- (void)animateNavBarTo:(CGFloat)y
{
[UIView animateWithDuration:0.2 animations:^{
CGRect frame = self.navigationController.navigationBar.frame;
CGFloat alpha = (frame.origin.y >= y ? 0 : 1);
frame.origin.y = y;
[self.navigationController.navigationBar setFrame:frame];
[self updateBarButtonItems:alpha];
}];
}
如果需要稍微不同的行为,可以用以下代码替换在滚动时重新定位进度条的那一行(即 scrollViewDidScroll
函数中的 else
块):
frame.origin.y = MIN(20,
MAX(-size, frame.origin.y -
(frame.size.height * (scrollDiff / scrollHeight))));
customView
应该不太困难。 - WayneScrollView
的contentSize
比frame小,则滑动动画将不起作用。同时,请确保在viewDidDisappear
中将所有导航项的alpha重置为1.0。 - LegolessscrollView
没有显示时随时发生。 - Wayneself.navigationController.hidesBarsOnSwipe = YES;
对我来说可行。
如果你在编写 Swift 代码,你必须使用这种方法(参考自https://dev59.com/QWIj5IYBdhLWcg3w24kF#27662702)
navigationController?.hidesBarsOnSwipe = true
这里还有一个实现:TLYShyNavBar v1.0.0 发布!
在尝试了已有的解决方案之后,我决定自己动手写一个。对我来说,它们要么表现不佳,要么有很高的入门门槛和样板代码,要么缺少导航栏下方的扩展视图。要使用此组件,您只需执行以下操作:
self.shyNavBarManager.scrollView = self.scrollView;
噢,而且它在我们自己的应用程序中经过了战斗考验。
UICollectionViewController
的extendedLayoutIncludesOpaqueBars
属性被设置为YES
。 - Tim ArnoldiOS8包含获取导航栏隐藏的属性。有一个WWDC视频演示了它,搜索"iOS 8中的视图控制器改进"。
class QuotesTableViewController: UITableViewController {
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
navigationController?.hidesBarsOnSwipe = true
}
}
其他属性:
class UINavigationController : UIViewController {
//... truncated
/// When the keyboard appears, the navigation controller's navigationBar toolbar will be hidden. The bars will remain hidden when the keyboard dismisses, but a tap in the content area will show them.
@availability(iOS, introduced=8.0)
var hidesBarsWhenKeyboardAppears: Bool
/// When the user swipes, the navigation controller's navigationBar & toolbar will be hidden (on a swipe up) or shown (on a swipe down). The toolbar only participates if it has items.
@availability(iOS, introduced=8.0)
var hidesBarsOnSwipe: Bool
/// The gesture recognizer that triggers if the bars will hide or show due to a swipe. Do not change the delegate or attempt to replace this gesture by overriding this method.
@availability(iOS, introduced=8.0)
var barHideOnSwipeGestureRecognizer: UIPanGestureRecognizer { get }
/// When the UINavigationController's vertical size class is compact, hide the UINavigationBar and UIToolbar. Unhandled taps in the regions that would normally be occupied by these bars will reveal the bars.
@availability(iOS, introduced=8.0)
var hidesBarsWhenVerticallyCompact: Bool
/// When the user taps, the navigation controller's navigationBar & toolbar will be hidden or shown, depending on the hidden state of the navigationBar. The toolbar will only be shown if it has items to display.
@availability(iOS, introduced=8.0)
var hidesBarsOnTap: Bool
/// The gesture recognizer used to recognize if the bars will hide or show due to a tap in content. Do not change the delegate or attempt to replace this gesture by overriding this method.
@availability(iOS, introduced=8.0)
unowned(unsafe) var barHideOnTapGestureRecognizer: UITapGestureRecognizer { get }
}
通过http://natashatherobot.com/navigation-bar-interactions-ios8/发现。
这适用于iOS 8及以上版本,并确保状态栏仍保留其背景
self.navigationController.hidesBarsOnSwipe = YES;
CGRect statuBarFrame = [UIApplication sharedApplication].statusBarFrame;
UIView *statusbarBg = [[UIView alloc] initWithFrame:statuBarFrame];
statusbarBg.backgroundColor = [UIColor blackColor];
[self.navigationController.view addSubview:statusbarBg];
如果您希望在点击状态栏时显示导航栏,可以执行以下操作:
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {
self.navigationController.navigationBarHidden = NO;
}
我有一种简单的解决方法,没有进行深入测试,但是以下是我的想法:
该属性将保留导航栏中的所有项目,适用于我的UITableViewController类。
@property (strong, nonatomic) NSArray *navBarItems;
在同一个UITableViewController类中,我有:
-(void)scrollViewDidScrollToTop:(UIScrollView *)scrollView
{
if([[[UIDevice currentDevice] systemVersion] floatValue] < 7.0f){
return;
}
CGRect frame = self.navigationController.navigationBar.frame;
frame.origin.y = 20;
if(self.navBarItems.count > 0){
[self.navigationController.navigationBar setItems:self.navBarItems];
}
[self.navigationController.navigationBar setFrame:frame];
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if([[[UIDevice currentDevice] systemVersion] floatValue] < 7.0f){
return;
}
CGRect frame = self.navigationController.navigationBar.frame;
CGFloat size = frame.size.height - 21;
if([scrollView.panGestureRecognizer translationInView:self.view].y < 0)
{
frame.origin.y = -size;
if(self.navigationController.navigationBar.items.count > 0){
self.navBarItems = [self.navigationController.navigationBar.items copy];
[self.navigationController.navigationBar setItems:nil];
}
}
else if([scrollView.panGestureRecognizer translationInView:self.view].y > 0)
{
frame.origin.y = 20;
if(self.navBarItems.count > 0){
[self.navigationController.navigationBar setItems:self.navBarItems];
}
}
[UIView beginAnimations:@"toggleNavBar" context:nil];
[UIView setAnimationDuration:0.2];
[self.navigationController.navigationBar setFrame:frame];
[UIView commitAnimations];
}
这只适用于ios >= 7,我知道它很丑,但这是一种快速实现的方法。欢迎提出任何评论/建议 :)
KVO
观察 UIScrollView
的状态,因此不需要使用代理(并且您可以将此代理用于其他任何所需的内容)。- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
if (fabs(velocity.y) > 1)
[self hideTopBar:(velocity.y > 0)];
}
- (void)hideTopBar:(BOOL)hide
{
[self.navigationController setNavigationBarHidden:hide animated:YES];
[[UIApplication sharedApplication] setStatusBarHidden:hide withAnimation:UIStatusBarAnimationSlide];
}
UITableView
的UIScrollViewDelegate
。- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
在UIScrollViewDelegate
方法中,您可以获取新的contentOffset并相应地将UINavigationBar
向上或向下平移。
根据一些阈值和因子,您可以设置和计算子视图的alpha值。
希望这能有所帮助!