使用自定义模式演示处理通话状态栏
Posted
技术标签:
【中文标题】使用自定义模式演示处理通话状态栏【英文标题】:Handling In-Call Status Bar with Custom Modal Presentation 【发布时间】:2014-02-26 20:37:23 【问题描述】:问题
我注意到在通话期间使用UIViewControllerAnimatedTransitioning
呈现UINavigationController
(带有根视图控制器,自然已经推送)时出现了一些奇怪的行为。
*注意:这是在模拟器上测试的,因为启用/禁用通话状态栏很容易,但测试人员在实际手机上观察到了这种现象。
我的(部分)解决方法
如果状态栏的高度异常,我通过在演示期间调整控制器的框架解决了这个问题:
@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
(参见问题的第二点)。如果其他人遇到此问题并找到了更好的方法,我将不胜感激。
【问题讨论】:
你找到解决方法了吗?我的问题是我的应用程序的主屏幕没有导航栏,带有一个有导航栏的滑入式面板。滑入式面板全屏时,通话中的绿色条显示,面板变短,但滑入式面板部分屏幕时,通话进度条消失。因此,当我打开和关闭面板时,面板会变得越来越短。 @MusiGenesis 我还没有找到解决办法,但 Apple 确实开始查看我的错误报告。如果他们确认这确实是一个错误,我会在这里发布。 @Austin 你找到解决办法了吗? @tikhop 我从未找到解决方案,Apple 也从未回复我的错误报告。它可能在 ios 8 中被修复;应用程序的设计发生了变化,因此不再需要自定义演示控制器,因此我没有对其进行测试。 @Austin,感谢您的回复。所以在 iOS8 中没有任何修复,我遇到了同样的问题,只找到了一个看起来像你的解决方案。 【参考方案1】:我花了太多时间来解决状态栏高度问题,并提出了一个适合我的通用解决方案,我认为也适用于您的情况。
首先,关于状态栏的一些奇怪的事情。
通常高 20 点,屏幕通常高 568 点
“通话中”时,状态栏高40点,屏幕高548点
隐藏状态栏时,状态栏高度为 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];
【讨论】:
updateViews
到底是做什么的?您要将通知观察添加到哪个类?
@George 我本可以更好地解释这一点。 updateViews
是通用的,用于更新您拥有的任何视图的布局。 layoutSubviews
在 UIView
上工作,但在视图控制器上没有任何可比性,因此在视图控制器的视图上调用 layoutSubviews
会起作用。【参考方案2】:
我遇到了同样的问题,问题在于我展示的视图由于通话栏而自动调整了 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]
【讨论】:
【参考方案3】:只需在 layoutSubviews 中设置框架,因为它在状态栏高度发生变化时被调用。一般来说,根据经验,仅在 layoutSubviews 中进行所有框架设置。
【讨论】:
【参考方案4】:这是我在我的应用程序委托中放入的一种解决方法,它为我解决了问题:
- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
if (newStatusBarFrame.size.height < 40)
for (UIView *view in self.window.subviews)
view.frame = self.window.bounds;
【讨论】:
【参考方案5】:我遇到了同样的问题,我通过调用更新框架视图修复了它,所以我得到了高度状态栏。我的问题解决了。
UIView *toViewSnapshot = [toView resizableSnapshotViewFromRect:toView.frame afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
【讨论】:
以上是关于使用自定义模式演示处理通话状态栏的主要内容,如果未能解决你的问题,请参考以下文章