使用自定义模式演示处理呼叫状态栏

时间:2014-02-26 20:37:24

标签: ios uiview ios7 modalviewcontroller ios7-statusbar

问题

我在电话呼叫期间使用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(见问题的第二点)。如果其他人遇到这个问题并找到了更好的方法,我将非常感谢一个解决方案。

5 个答案:

答案 0 :(得分:3)

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

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

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

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

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

  4. 如果状态栏发生变化但您没有更新屏幕的高度,那么计算将会关闭,这可以在一些非常大的名称(甚至默认)应用程序中看到。

    因此,我提出的解决方案有两个方面: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];
    

答案 1 :(得分: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]
}

答案 2 :(得分:0)

只需在状态栏高度更改时调用layoutSubviews中的框架。通常,根据经验,只在layoutSubviews中进行所有帧设置。

答案 3 :(得分:0)

这是我在我的应用代理中添加的解决方法,为我解决了问题:

Data d = ....... //Get a data from somewhere
if(d.isImage()) {
    Image img = d.asImage();
    //...
} else if (d.isString()) {
    String string = d.asString();
    //...
} else if (d.isInteger()) {
    Integer i = d.asInt();
    //...
} else {
    throw new RuntimeException("Illegal data " + d + " received");
}

答案 4 :(得分:0)

我遇到了同样的问题,并通过调用更新框架视图进行了修复,因此获得了高度状态栏。我的问题解决了。

 UIView *toViewSnapshot = [toView resizableSnapshotViewFromRect:toView.frame afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];