iOS in-Call指标正在下调视图/内容,修改根视图`frame`

时间:2018-02-01 17:07:26

标签: ios objective-c

我遇到的问题是我的根视图(UIViewController视图)被呼入指示符下推:window.rootViewController.view.frame正在进行修改(Y设置为20)。当我自己回复did/willStatusBarFrameChange时,我不想要这种行为。

我正在寻找可以阻止修改帧以响应通话中状态栏的属性或设置。我使用其他API来响应顶部/底部框架和iPhone X安全区域的变化。

我已经尝试了autoResizingMaskextendedLayoutIncludesOpaqueBarsedgesForExtendedLayoutviewRespectsSystemMinimumLayoutMargins之类的内容,但无法正常工作。

如果相关,该视图也会动画下来,表明它不是一些副作用,而是某个地方的预期行为。

我已经阅读了许多类似行为的报告,但尚未弄清楚他们是否真正解决了这个问题和/或解决方案实际上是什么(每个解决方案似乎都解决了一个稍微不同的问题)。

相关问题:Prevent In-Call Status Bar from Affecting View(答案详情不足),Auto Layout and in-call status bar(不清楚如何改编)

-

我无法提供简单的复制,但设置视图的代码部分看起来像这样:

窗口设置:

uWindow* window = [[uContext sharedContext] window];
window.rootViewController = (UIViewController*)[[UIApplication sharedApplication] delegate];
[window makeKeyAndVisible];

我们的AppDelegate实施(相关部分)

@interface uAppDelegate : UIViewController<@(AppDelegate.Implements:Join(', '))>

...

@implementation uAppDelegate
- (id)init
{
    CGRect screenBounds = [UIScreen mainScreen].bounds;
    uWindow* window = [[uWindow alloc] initWithFrame:screenBounds];
    return self;
}

我们将根视图分配给上面的委托,即UIViewController的.view属性。

@interface OurRootView : UIControl<UIKeyInput>

UIControl* root = [[::OurRootView alloc] init];
[root setUserInteractionEnabled: true];
[root setMultipleTouchEnabled: true];
[root setOpaque: false];
[[root layer] setAnchorPoint: { 0.0f, 0.0f }];
// some roundabout calls that make `root` the `rootViewController.view = root`
[root sizeToFit];

目标是OurRootView始终占据整个屏幕空间,无论调整哪些帧/控制/边距。我使用其他API来检测这些帧并相应地调整内容。我没有使用任何其他控制器,视图或布局。

3 个答案:

答案 0 :(得分:1)

目前还不清楚是否有标志可以禁用此行为。然而,我找到了一种否定效果的方法。

通过修改根视图的frame,导致帧向下移动的是什么。可以覆盖此设置器并阻止移动。在我们的例子中,根视图固定在位,因此我这样做了:

@implementation OurRootView

- (void)setFrame:(CGRect)frame;
{
    frame.origin.y = 0;
    [super setFrame:frame];
}
@endf

当显示通话中显示时,这会将视图保持在固定位置(我们通过更改statusBarFrame和/或safeAreaInsets来处理新大小)。 我不知道为什么这也会避免帧的动画,但确实如此。

如果由于某种原因你无法覆盖setFrame,你可以通过覆盖app委托的didChangeStatusBarFrame并修改根视图的框架(将原点设置回0)来获得接近相似的效果。动画仍然以这条路线播放。

答案 1 :(得分:0)

我希望我理解你的问题:如果你有一些像incall这样的指标,或者在我的情况下使用地图。您需要在启动应用程序时检测到有一些指示符并重新设置整个窗口的框架。我的解决方案:

didFinishLaunchingWithOptions中,您检查状态栏的框架,因为incall是状态栏的一部分。

CGFloat height = [UIApplication sharedApplication].statusBarFrame.size.height;
    if (height == 20) {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    }
    else {
        CGRect frame = [[UIScreen mainScreen] bounds];
        frame.size.height = frame.size.height - height +20;
        frame.origin.y = height-20;
        self.window = [[UIWindow alloc] initWithFrame:frame];
    }

答案 2 :(得分:0)

您可以在视图控制器中收听通知UIApplicationDidChangeStatusBarFrameNotification,以便在状态栏更改时捕获。然后调整视图控制器的主视图矩形以始终覆盖整个屏幕。

// Declare in your class
@property (strong, nonatomic) id<NSObject> observer;

- (void)viewDidLoad {
    [super viewDidLoad];

    _observer = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidChangeStatusBarFrameNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
        CGFloat newHeight = self.view.frame.size.height + self.view.frame.origin.y;
        self.view.frame = CGRectMake(0.0, 0.0, self.view.frame.size.width, newHeight);
    }];
}

-(void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:_observer];
}

我在各种型号上试过它,据我所知,它运行正常。在iPhone X上,通知未发布,因为它不会改变呼叫的状态栏高度。

如果您想以某种方式准备视图,还会在状态栏更改之前触发相应的UIApplicationWillChangeStatusBarFrameNotification