34

问题

我注意到在通话期间呈现UINavigationController(带有根视图控制器,自然已经推送)时出现了一些奇怪的行为。UIViewControllerAnimatedTransitioning

  • 如果在呈现导航控制器后启用通话状态栏,则导航控制器会按预期向下移动其视图。但是当通话结束时,控制器不会将其视图重新向上移动,在状态栏下方留下 20p 的间隙。
  • 如果在呈现控制器之前启用通话状态栏,则控制器根本不考虑状态栏,留下 44p 高导航栏的 4p 从 40p 状态栏下方窥视。当通话结束时,控制器将其视图向下移动以适应正常的 20p 状态栏。

*注意:这是在模拟器上测试的,因为启用/禁用通话状态栏很容易,但测试人员在实际手机上观察到了这种现象。

我的(部分)解决方法

如果状态栏的高度异常,我通过在演示期间调整控制器的框架来解决这个问题:

@interface CustomAnimationController : NSObject <UIViewControllerAnimatedTransitioning>
@end

@implementation CustomAnimationController

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController *toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *container = [transitionContext containerView];

    CGRect frame = [transitionContext finalFrameForViewController:toController];
    if (CGRectEqualToRect(frame, CGRectZero))
    {
        // In my experience, the final frame is always a zero rect, so this is always hit
        UIEdgeInsets insets = UIEdgeInsetsZero;
        // My "solution" was to inset the container frame by the difference between the 
        // actual status bar height and the normal status bar height
        insets.top = CGRectGetHeight([UIApplication sharedApplication].statusBarFrame) - 20;
        frame = UIEdgeInsetsInsetRect(container.bounds, insets);
    }

    toController.view.frame = frame;
    [container addSubview:toController.view];

    // Perform whiz-bang animation here
}    

@end

此解决方案确保导航栏位于状态栏下方,但导航控制器在通话结束时仍无法自行恢复。所以该应用程序至少可以使用,但通话结束后导航栏上方有一个难看的 20p 间隙。

有没有更好的办法?

我是否错过了一些关键步骤来确保导航控制器自己负责通话状态栏?当使用内置的模态演示样式呈现时,它工作得很好。

在我看来,这有点像 UIKit 错误——毕竟,导航控制器似乎收到了UIApplicationWillChangeStatusBarFrameNotification(参见问题的第二点)。如果其他人遇到此问题并找到了更好的方法,我将不胜感激。

4

5 回答 5

3

我花了太多时间来解决状态栏高度问题,并提出了一个适用于我的通用解决方案,我认为也适用于您的情况。

首先,关于状态栏的一些奇怪的事情。

  1. 它通常是 20 点高,屏幕通常是 5 6 8 点高

  2. “通话中”时,状态栏高 40 点,屏幕高 5 4 8 点

  3. 隐藏状态栏时,状态栏高度为 0 点,屏幕高度为 5 6 8 点

如果状态栏发生变化但您不更新屏幕高度,则计算将关闭,这可以在一些非常知名(甚至默认)的应用程序中看到。

所以,我想出的解决方案有两个: 1. 创建一个宏来获取调整后的屏幕高度 2. 注册一个通知以在状态栏更改时更新视图。

这是宏,我建议将它们放入您的prefix文件中

#define kScreenWidth     [UIScreen mainScreen].bounds.size.width
#define kStatusBarHeight (([[UIApplication sharedApplication] statusBarFrame].size.height == 20.0f) ? 20.0f : (([[UIApplication sharedApplication] statusBarFrame].size.height == 40.0f) ? 20.0f : 0.0f))
#define kScreenHeight    (([[UIApplication sharedApplication] statusBarFrame].size.height > 20.0f) ? [UIScreen mainScreen].bounds.size.height - 20.0f : [UIScreen mainScreen].bounds.size.height)

此外,这是我发现在状态栏更改时 100% 对我有用的通知中心呼叫。

NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self.view selector:@selector(layoutSubviews) name:UIApplicationWillChangeStatusBarFrameNotification object:nil];
于 2015-02-13T23:32:50.280 回答
1

我遇到了同样的问题,问题在于我展示的视图由于通话栏而自动调整了 20pt。但是,由于我将视图插入到容器中,因此我不得不重置框架以匹配容器的边界。

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    UIView* destinationView = [transitionContext viewForKey:UITransitionContextToViewKey];
    UIView* container = transitionContext.containerView;

    // Make sure destination view matches container bounds
    // This is necessary to fix the issue with in-call bar
    // which adjusts the view's frame by 20pt.
    destinationView.frame = container.bounds;

    // Add destination view to container
    [container insertSubview:destinationView atIndex:0];

    // [reducted]
}
于 2016-03-27T10:07:17.537 回答
0

只需在状态栏高度更改时调用 layoutSubviews 中的框架即可。一般来说,根据经验,仅在 layoutSubviews 中进行所有框架设置。

于 2015-02-16T14:19:13.217 回答
0

这是我在我的应用程序委托中放入的解决方法,它为我解决了问题:

- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
{
    if (newStatusBarFrame.size.height < 40) {
        for (UIView *view in self.window.subviews) {
            view.frame = self.window.bounds;
        }
    }
}
于 2016-01-10T22:28:07.703 回答
0

我有同样的问题,我通过调用更新框架视图修复了它,所以我得到了高度状态栏。我的问题解决了。

 UIView *toViewSnapshot = [toView resizableSnapshotViewFromRect:toView.frame afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
于 2018-06-21T03:04:40.943 回答