首页 文章

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

提问于
浏览
34

问题

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

  • 如果在显示导航控制器后启用了呼叫状态栏,导航控制器将按预期向下移动其视图 . 但是当呼叫结束时,控制器不会将其视图向上移动,在状态栏下留下20p的间隙 .

  • 如果在显示控制器之前启用了通话中状态栏,则控制器根本不会考虑状态栏,而是从40p状态栏下方留下4p的44p高导航栏 . 通话结束后,控制器将其视图向下移动以适应正常的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

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

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

    • 通常高20点,屏幕通常高5点,高度为8点

    • 在"in-call"时,状态栏为40点高,屏幕为5 4 8点高

    • 状态栏隐藏时,状态栏高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];
    
  • 3

    我遇到了同样的问题,问题在于我所呈现的视图因为在电话栏中而被自动调整了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]
    }
    
  • 0

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

  • 1

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

    - (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
    {
        if (newStatusBarFrame.size.height < 40) {
            for (UIView *view in self.window.subviews) {
                view.frame = self.window.bounds;
            }
        }
    }
    
  • 0

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

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

相关问题