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



问题

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

  • 如果在显示导航控制器后启用了调用中状态栏,则导航控制器会按预期向下移动其视图。但当呼叫结束时,控制器不会将其视图向上移动,在状态栏下留下20便士的间隙
  • 如果在显示控制器之前启用了呼叫中状态栏,则控制器根本不考虑状态栏,使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

此解决方案确保导航栏位于状态栏下方,但在呼叫结束时,导航控制器仍无法将自己移回原位。因此,该应用程序至少是可用的,但在通话结束后,导航栏上方有一个20便士的缺口。

有更好的方法吗

我是不是错过了一些关键步骤,以确保导航控制器自行处理呼叫中的状态栏?当使用内置的模态表示样式时,它工作得很好。

在我看来,这有点像UIKit错误——毕竟,导航控制器似乎接收到了UIApplicationWillChangeStatusBarFrameNotification(请参阅问题的第二点)。如果其他人遇到过这个问题,并找到了更好的方法,我将非常感谢您的解决方案。

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

首先,关于状态栏有一些奇怪的地方。

  1. 它通常有20点高,屏幕通常有568点高

  2. 当"呼叫中"时,状态栏高40点,屏幕高548点

  3. 当状态栏隐藏时,状态栏为0点高,屏幕为568点高

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

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

我也遇到了同样的问题,问题是我所呈现的视图由于在调用栏中而自动调整了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]
}

只需在layoutSubviews中设置框架,就像状态栏高度更改时所调用的那样。通常,根据经验,只在布局子视图中进行所有框架设置。

以下是我在应用程序委托中为我解决问题的解决方法:

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

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

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

相关内容

  • 没有找到相关文章

最新更新