我想隐藏状态栏文本而不删除状态栏本身。
我在整个屏幕上呈现一个新的视图控制器,当视图控制器占据整个屏幕时,我不希望状态栏文本可见。请注意,呈现视图控制器具有UINavigationBar
,而呈现的视图控制器则不具有true
。
我尝试在prefersStatusBarHidden
中简单地返回modalPresentationCapturesStatusBarAppearance
,但这会导致状态栏框被删除,导致呈现视图控制器上的导航控制器向上滑动,这在新的时候可见视图控制器仍然从底部开始动画。
然后我尝试为显示的视图控制器设置true
到false
,然后在prefersStatusBarHidden
中返回.Fade
,在preferredStatusBarUpdateAnimation
中返回setNeedsStatusBarAppearanceUpdate()
,在viewDidAppear
中调用prefersStatusBarHidden
,但这会导致状态栏文本从白色变为黑色并保持可见状态。将true
设置为{{1}}会删除状态栏,就像我之前提到的那样。
理想情况下,当我启动segue时,我会开始淡化状态栏上的文本,并且当动画完成时,alpha将达到0。然后解雇后重新回到alpha 1.这或类似的解决方案是否可行?我只需要支持iOS 8 +。
答案 0 :(得分:1)
解决方案1 :我所拥有的解决方案非常hacky,但它确实有效。首先,呈现的视图控制器应将modalPresentationCapturesStatusBarAppearance
设置为YES
,并应为YES
返回prefersStatusBarHidden
。
现在,问题是不要让导航栏向上滑动。要执行此操作,请先定义UINavigationBar
子类并覆盖setFrame:
,setBounds:
和setCenter:
,以便即使在想要向上滑动时也能保持导航栏的形状和位置不变状态栏隐藏时。像这样:
const CGFloat kStatusBarHeight = 20;
const CGFloat kDefaultNavigationBarHeight = 44;
const CGFloat kLandscapeNavigationBarHeight = 32;
...
- (void)setCenter:(CGPoint)center {
center = [self forcedCenterForCenter:center];
[super setCenter:center];
}
- (void)setBounds:(CGRect)bounds {
bounds = [self forcedBoundsForBounds:bounds];
[super setBounds:bounds];
}
- (void)setFrame:(CGRect)frame {
frame = [self forcedFrameForFrame:frame];
[super setFrame:frame];
}
- (CGPoint)forcedCenterForCenter:(CGPoint)center {
if (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)) {
center.y = kStatusBarHeight + kDefaultNavigationBarHeight * 0.5;
}
else {
// No status bar in landscape orientation in iOS 8.
center.y = kLandscapeNavigationBarHeight * 0.5;
}
return center;
}
- (CGRect)forcedBoundsForBounds:(CGRect)bounds {
if (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)) {
bounds.size.height = kDefaultNavigationBarHeight;
}
else {
bounds.size.height = kLandscapeNavigationBarHeight;
}
return bounds;
}
- (CGRect)forcedFrameForFrame:(CGRect)frame {
if (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)) {
frame.origin.y = kStatusBarHeight;
frame.size.height = kDefaultNavigationBarHeight;
}
else {
// No status bar in landscape orientation in iOS 8.
frame.origin.y = 0.0;
frame.size.height = kLandscapeNavigationBarHeight;
}
return frame;
}
我们打电话给这个班级ForcedNavigationBar
。如果您只是将此课程传递到UINavigationController
的{{1}},则导航栏将保留在原位,但您会遇到其他问题。首先,有时,导航栏不会向上延伸以覆盖状态栏。其次,推入导航控制器的视图控制器不应再使用其initWithNavigationBarClass:toolbarClass:
属性来进行布局,因为topLayoutGuide
可能会考虑实际上已隐藏的状态栏,即使我们总是强制空间对于想象中的状态栏。
要解决第一个问题,首先要将topLayoutGuide
属性设置为ForcedNavigationBar
并覆盖backgroundColor
,使[UIColor clearColor]
的背景不可见(不要调用drawRect:
super
)。 (导航栏的按钮仍然可见。)现在,我们在真实的导航栏下面放置一个虚拟导航栏,以提供一个背景,它总是为虚构的状态栏提供空间。我们可以通过继承UINavigationController
(称之为ForcedNavigationBar
)并向虚拟导航栏添加约束来实现此目的:
- (void)viewDidLoad {
[super viewDidLoad];
UINavigationBar * backgroundNavigationBar = [[UINavigationBar alloc] init];
[self.navigationBar.superview insertSubview:backgroundNavigationBar belowSubview:self.navigationBar];
{
backgroundNavigationBar.translatesAutoresizingMaskIntoConstraints = NO;
// The background bar always hugs the top of the screen.
NSLayoutConstraint * topConstraint = [NSLayoutConstraint constraintWithItem:backgroundNavigationBar
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1
constant:0];
[self.view addConstraint:topConstraint];
NSLayoutConstraint * bottomConstraint = [NSLayoutConstraint constraintWithItem:backgroundNavigationBar
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.navigationBar
attribute:NSLayoutAttributeBottom
multiplier:1
constant:0];
[self.navigationBar.superview addConstraint:bottomConstraint];
NSLayoutConstraint * leftConstraint = [NSLayoutConstraint constraintWithItem:backgroundNavigationBar
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.navigationBar
attribute:NSLayoutAttributeLeft
multiplier:1
constant:0];
[self.navigationBar.superview addConstraint:leftConstraint];
NSLayoutConstraint * rightConstraint = [NSLayoutConstraint constraintWithItem:backgroundNavigationBar
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.navigationBar
attribute:NSLayoutAttributeRight
multiplier:1
constant:0];
[self.navigationBar.superview addConstraint:rightConstraint];
}
}
要解决第二个问题,您只需不要使用topLayoutGuide
并根据您想要定位导航栏的位置在顶部设置空间。对于非滚动视图的视图,您可以更新相对于viewWillLayoutSubviews
中导航栏定位它们的约束。如果您有滚动视图(如表格视图),则可以在contentInset
中调整其viewDidLayoutSubviews
的顶部。 (以前,您可以将滚动视图的contentInset
的顶部设置为topLayoutGuide.length
。)
我提供的代码可以在iPhone 5屏幕上运行。在iOS 8中,您必须使此代码“自适应”,因此它仍然可以在iPhone 6屏幕上运行。例如,在横向方向上,导航栏可能不会在iPhone 6上被压扁。
编辑:解决方案2 :使用snapshotViewAfterScreenUpdates
拍摄展示视图控制器的快照视图,并在呈现或解除之前将其插入视图层次结构中。这样,您不必担心导航栏向上或向下滑动。 (我没有亲自试过这个,但看起来很有希望。)
编辑2:此解决方案的一个小问题是导航栏在解雇之前没有状态栏的空间。如果您使用UIViewControllerAnimatedTransitioning
解雇,则使用空动画块调用[UIView animationWithDuration:...]
似乎(某种程度上)强制系统让“to”视图控制器(导航控制器)指示状态栏外观。然后,为了使“to”视图控制器布局并带有状态栏的空间,可以在容器视图或某个视图上调用layoutIfNeeded
,并在其中查看“to”视图中的控制器。在animateTransition:
中完成所有这些操作,但在此方法中实际执行动画之前。
答案 1 :(得分:1)
实际上,您可以直接使用状态栏访问窗口,并随意使用它。
- (UIWindow *)statusBarWindow
{
return (UIWindow *)[[UIApplication sharedApplication] valueForKey:@"statusBarWindow"];
}
当然,它是无证件的功能,在App Review Process方面可能很危险,但我只有积极的经验。