在通话状态栏中(无法满足约束条件) [英] In Call Status Bar (Unable to Satisfy Constraints)

查看:163
本文介绍了在通话状态栏中(无法满足约束条件)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

就像这个问题:



下面是显示In Call Status Bar之前的样子:





发生错误后状态栏的背景蓝色是根视图控制器的背景颜色。



每当显示呼叫状态栏时,将打印出以下错误:

 无法同时满足约束条件。 
可能至少以下列表中的一个约束是您不想要的约束。试试这个:(1)看看每个约束并试着找出你不期望的东西; (2)找到添加了不需要的约束或约束的代码并修复它。 (注意:如果你看到你不理解的NSAutoresizingMaskLayoutConstraints,请参阅UIView属性translatesAutoresizingMaskIntoConstraints的文档)

< NSLayoutConstraint:0x7fdac6192320 V:| - (20) - [ UIInputSetContainerView:0x7fdac6190a40](名称:'|':UITextEffectsWindow:0x7fdac6061a10)>,
< NSLayoutConstraint:0x7fdac608ebb0'UIInputWindowController-top'V:| - (0) - [UIInputSetContainerView:0x7fdac6190a40](名称: '|':UITextEffectsWindow:0x7fdac6061a10)>


将尝试通过违反约束来恢复
< NSLayoutConstraint:0x7fdac6192320 V:| - (20) - [UIInputSetContainerView :0x7fdac6190a40](名称:'|':UITextEffectsWindow:0x7fdac6061a10)>

在UIViewAlertForUnsatisfiableConstraints上创建一个符号断点,以便在调试器中捕获它。
< UIKit / UIView.h>中列出的UIView上的UIConstraintBasedLayoutDebugging类别中的方法也可能有所帮助。

无法同时满足约束条件。
可能至少以下列表中的一个约束是您不想要的约束。试试这个:(1)看看每个约束并试着找出你不期望的东西; (2)找到添加了不需要的约束或约束的代码并修复它。 (注意:如果你看到你不理解的NSAutoresizingMaskLayoutConstraints,请参阅UIView属性translatesAutoresizingMaskIntoConstraints的文档)

< NSLayoutConstraint:0x7fc60b03d230 V:| - (20) - [ UIInputSetContainerView:0x7fc608d22020](名称:'|':UITextEffectsWindow:0x7fc60b171720)>,
< NSLayoutConstraint:0x7fc60b03d2d0 UIInputSetContainerView:0x7fc608d22020.bottom == UITextEffectsWindow:0x7fc60b171720.bottom>,
< ; NSLayoutConstraint:0x7fc60b17c4b0'UIInputWindowController-height'UIInputSetContainerView:0x7fc608d22020.height == UITextEffectsWindow:0x7fc60b171720.height>


将尝试通过违反约束来恢复
< NSLayoutConstraint :0x7fc60b03d2d0 UIInputSetContainerView:0x7fc608d22020.bottom == UITextEffectsWindow:0x7fc60b171720.bottom>

在UIViewAlertForUnsatisfiableConstraints上创建一个符号断点,以便在调试器中捕获它。
< UIKit / UIView.h>中列出的UIView上的UIConstraintBasedLayoutDebugging类别中的方法也可能有所帮助。

使用FLEX调试工具我可以看到



UINavigationBarBackground UIStatusBarForegroundView 在In Call Status Bar之前重叠,但之后 UINavigationBarBackground 低于 UIStatusBarForegroundView



此错误仅在我呈现模态视图控制器后发生。如果我显示呼叫状态栏,则不会发生此问题。显示模态视图控制器后,您无法返回到根视图控制器。



我该怎么做才能解决这个问题?

解决方案

iOS 9.2.1,Xcode 7.2.1,启用ARC



更新3/25/2016:冲突仍然存在Xcode 7.3,iOS 9.3。



摘要:在应用程序的窗口层次结构中,有各种窗口被添加到应用程序窗口中。在我的例子中,这是 UITextEffectsWindow UIRemoteKeyboardWindow 。这些窗口具有预配置的约束。似乎有一个错误更新了一些垂直布局约束,但没有更新同一窗口的其他相关约束。这会在调试器中抛出约束冲突。当自定义窗口添加到窗口层次结构中或者在模拟器和实际iOS设备上调用状态栏进入或退出时,会发生这种情况。



约束是优先级1000,这表明它们是必需的约束。



下面的解决方案将删除冲突的约束并在呼入状态栏后添加回来切换出来。



编辑2/25/2016: 两种解决方案都解决了已经显示通话中状态栏的问题打开应用程序时。冲突发生在状态栏更改之前。



看来这个约束冲突只在第一次显示通话中状态栏时发生(这是最常见的),或者在涉及呈现位于关键窗口顶部的附加自定义窗口的其他场景中。 我还尝试创建一个空白的单一视图应用程序,并且在通话中状态栏中没有添加任何切换,我也遇到了相同的约束冲突。



我认为这是一个错误,并在Dev论坛上进行了讨论。 Dev论坛的原始文章可以在这里找到(如matty所指出的):







解释约束错误后(请参阅此Apple文档以帮助解决此问题: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/DebuggingTricksandTips.html )我使用以下代码来消除冲突的约束:



Objective-C:



* AppDelegate.h

  ... 

@interface YourAppName:UIResponder < UIApplicationDelegate>
{
NSMutableDictionary * dictionaryConstraints;
}

...

* AppDelegate .m

  ... 

- (BOOL)申请:(UIApplication * )application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//在应用程序启动后覆盖自定义点。

dictionaryConstraints = [[NSMutableDictionary alloc] init];

返回true;

}

- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
{
NSLog(@newStatusBarFrame:% @,NSStringFromCGRect(newStatusBarFrame));

if(newStatusBarFrame.size.height> 20.0)
{
for([[UIApplication sharedApplication] windows]中的UIWindow *窗口)
{
if([window.class.description isEqual:@UITextEffectsWindow] || [window.class.description isEqual:@UIRemoteKeyboardWindow])
{
NSMutableArray * constraints = [[NSMutableArray alloc] initWithCapacity:[window.constraints count]];

for(NSLayoutConstraint * window.constraints中的约束)
{
if(!([constraint.description rangeOfString:@V:| - (0) - [UIInputSetContainerView ] .location == NSNotFound))
{
NSLog(@);
NSLog(@%@:%@,%f,%f,window.class.description,constraint.description,constraint.priority,constraint.constant);
NSLog(@);

[constraints addObject:constraint];
[window removeConstraint:constraint];
}
其他
{
nil;
}
}

if([constraints count]> 0)
{
[dictionaryConstraints setObject:constraints forKey:[NSString stringWithFormat:@ %p,窗口]];
}
其他
{
nil;
}
}
其他
{
nil;
}
}
}
其他
{
nil;
}
}

- (void)resetConstraints
{
for([[UIApplication sharedApplication] windows]中的UIWindow *窗口)
{
if([window.class.description isEqual:@UITextEffectsWindow] || [window.class.description isEqual:@UIRemoteKeyboardWindow])
{
if(dictionaryConstraints)
{
NSArray * keys = [dictionaryConstraints allKeys];

for(int i = 0; i< [keys count]; i ++)
{
if([[NSString stringWithFormat:@%p,window] isEqualToString :keys [i]])
{
[window addConstraints:[dictionaryConstraints objectForKey:keys [i]]];
}
其他
{
nil;
}
}
}
其他
{
nil;
}
}
其他
{
nil;
}
}
}

- (void)application:(UIApplication *)application didChangeStatusBarFrame:(CGRect)oldStatusBarFrame
{
NSLog (@oldStatusBarFrame:%@,NSStringFromCGRect(oldStatusBarFrame));

if(oldStatusBarFrame.size.height> 20.0)
{
if([dictionaryConstraints count]> 0)
{
[self resetConstraints ]。
[dictionaryConstraints removeAllObjects];
}
其他
{
nil;
}
}
其他
{
nil;
}

for([[UIApplication sharedApplication] windows]中的UIWindow *窗口)
{
if([window.class.description isEqual:@UITextEffectsWindow ] || [window.class.description isEqual:@UIRemoteKeyboardWindow])
{
for(NSLayoutConstraint * window.constraints中的约束)
{
if(!([ constraint.description rangeOfString:@V:| - (0) - [UIInputSetContainerView]。location == NSNotFound))
{
NSLog(@);
NSLog(@%@:%@,%f,%f,window.class.description,constraint.description,constraint.priority,constraint.constant);
NSLog(@);
}
其他
{
nil;
}

}
}
其他
{
nil;
}
}
}

...

Swift:



* AppDelegate.swift

  ... 

var dictionaryConstraints = [NSString:NSArray]();

...

func应用程序(应用程序:UIApplication,willChangeStatusBarFrame newStatusBarFrame:CGRect)
{
print(newStatusBarFrame:\(newStatusBarFrame)) )

if newStatusBarFrame.size.height> 20.0
{
for UIApplication.sharedApplication()中的窗口.windows
{
if((window.classForCoder.description()==UITextEffectsWindow)||(窗口。 classForCoder.description()==UIRemoteKeyboardWindow))
{
var constraints = [NSLayoutConstraint]()

for window.constraints中的约束
{
if(constraint.description.containsString(V:| - (0) - [UIInputSetContainerView))
{
print(\(window.classForCoder.debugDescription)),\(约束.description),\(constraint.priority),\(constraint.constant))

constraints.append(约束)
window.removeConstraint(约束)
}
else
{
// nil
}
}

if(constraints.count> 0)
{
dictionaryConstraints [NSString(格式:%p,unsafeAddressOf(窗口))] =约束
}
其他
{
/ / nil
}
}
else
{
// nil
}
}
}
else
{
// nil
}
}

func resetConstraints()
{
for UIApplication.sharedApplication()中的窗口.windows
{
if((window.classForCoder.description()==UITextEffectsWindow)||(window.classForCoder.description()==UIRemoteKeyboardWindow))
{
if(dictionaryConstraints.count> 0)
{
let keys = Array(dictionaryConstraints.keys)

for i in 0 ..< keys.count
{
if(NSString(格式:%p,unsafeAddressOf(window))== keys [i])
{
window.addConstraints(dictionaryConstraints [ keys [i]] as![NSLayoutConstraint])
}
else
{
// nil
}
}
}
else
{
// nil
}
}
else
{
// nil
}
}
}

func应用程序(应用程序:UIApplication,didChangeStatusBarFrame oldStatusBarFrame:CGRect)
{
print(oldStatusBarFrame:\(oldStatusBarFrame))

if(oldStatusBarFrame.size.height> 20.0)
{
if(dictionaryConstraints.count> 0)
{
self.resetConstraints()
dictionaryConstraints.removeAll()
}
else
{
// nil
}
}
else
{
// nil
}

for UIApplication.sharedApplication()中的窗口.windows
{
if((window.classForCoder.description()==UITextEffectsWindow )|| (window.classForCoder.description()==UIRemoteKeyboardWindow))
{
for window.constraints中的约束
{
if(constraint.description.containsString(V: | - (0) - [UIInputSetContainerView))
{
print(\(window.classForCoder.debugDescription),\(constraint.description),\(constraint.priority),\\ \\(constraint.constant))
}
else
{
// nil
}
}
}
else
{
// nil
}
}
}

...

注意:这会保留所有不冲突的约束。并且在冲突情况不再发生之后重新添加已删除的冲突约束,即调用状态栏。



UPDATE 2015年2月25日: 进一步测试...



我决定使用应用中的两种方法来隔离不断变化的约束。委托* .m文件:

  ... 

- (无效)申请:(UIApplication * )applicationChangeStatusBarFrame:(CGRect)newStatusBarFrame
{
NSLog(@New status bar frame:%@,NSStringFromCGRect(newStatusBarFrame));

for([[UIApplication sharedApplication] windows]中的UIWindow *窗口)
{
NSLog(@%@,%@,window.description,window.constraints) ;
}
}

- (void)application:(UIApplication *)application didChangeStatusBarFrame:(CGRect)oldStatusBarFrame
{
NSLog(@old status bar frame:%@,NSStringFromCGRect(oldStatusBarFrame));

for([[UIApplication sharedApplication] windows]中的UIWindow *窗口)
{
NSLog(@%@,%@,window.description,window.constraints) ;
}
}

...

当通话状态栏切换时,冲突的约束从以下变化:



UITextEffectsWindow:


< UITextEffectsWindow:0x7fbf994cc810; frame =(0 0; 320 568); opaque
= NO; autoresize = W + H; layer =< UIWindowLayer:0x7fbf994c8470 >>,



(< NSLayoutConstraint:0x7fbf99667eb0 V:| - (0) - [UIInputSetContainerView:0x7fbf99668ce0](姓名:
'| ':UITextEffectsWindow:0x7fbf994cc810)>,



... 省略



< NSLayoutConstraint:0x7fbf9966c800'UIInputWindowController-top'V:| - (0) - [UIInputSetContainerView:0x7fbf99668ce0](名称:
'|':UITextEffectsWindow:0x7fbf994cc810)>,



... 省略


UIRemoteKeyboardWindow:


< UIRemoteKeyboardWindow:0x7fbf994ceb80; frame =(0 0; 320 568);
opaque = NO; autoresize = W + H; layer =< UIWindowLayer:0x7fbf994cf190 >>,



(< NSLayoutConstraint:0x7fbf994cfb20 V:| - (0) - [UIInputSetContainerView:0x7fbf99744ec0](姓名:
'| ':UIRemoteKeyboardWindow:0x7fbf994ceb80)>,



... 省略



< NSLayoutConstraint:0x7fbf9966c800'UIInputWindowController-top'V:| - (0) - [UIInputSetContainerView:0x7fbf99668ce0](名称:'|':UITextEffectsWindow:0x7fbf994cc810)>,



... 省略


...并更改为:



UITextEffectsWindow:


< UITextEffectsWindow:0x7fbf994cc810; frame =(0 0; 320 568); opaque
= NO; autoresize = W + H; layer =< UIWindowLayer:0x7fbf994c8470 >>,



(< NSLayoutConstraint:0x7fbf99667eb0 V:| - ( 20 ) - [UIInputSetContainerView:0x7fbf99668ce0](名称:
'|':UITextEffectsWindow:0x7fbf994cc810)>,



... 省略



< NSLayoutConstraint:0x7fbf9966c800'UIInputWindowController-top'V:| - (0) - [UIInputSetContainerView:0x7fbf99668ce0](名称:
'|':UITextEffectsWindow:0x7fbf994cc810)>,



... 省略


UIRemoteKeyboardWindow:


< UIRemoteKeyboardWindow:0x7fbf994ceb80; frame =(0 0; 320 568);
opaque = NO; autoresize = W + H; layer =< UIWindowLayer:0x7fbf994cf190 >>,



(< NSLayoutConstraint:0x7fbf994cfb20 V:| - ( 20 ) - [UIInputSetContainerView:0x7fbf99744ec0](名称:
'|':UIRemoteKeyboardWindow:0x7fbf994ceb80)>,



... 省略



< NSLayoutConstraint:0x7fbf9966c800'UIInputWindowController-top'V:| - (0) - [UIInputSetContainerView:0x7fbf99668ce0](名称:'|':UITextEffectsWindow:0x7fbf994cc810)>,



... 省略


了解视觉格式语言阅读 https://developer.apple.com/ library / ios / documentation / UserExperience / Conceptual / AutolayoutPG / VisualFormatLanguage.html



垂直布局V中的垂直布局约束似乎: TOPFIELD] - XX- [bottomField]从...更改


NSLayoutConstraint:0x7fbf99667eb0
V:| - (0) - [UIInputSetContainerView :0x7fbf99668ce0]


to ...


NSLayoutConstraint:0x7fbf99667eb0
V:| - (20) - [UIInputSetContainerView:0x7fbf99668ce0]


...两者都是windows:UITextEffectsWindow和UIRemoteKeyboardWindow;然而,...


NSLayoutConstraint:0x7fbf9966c800'UIInputWindowController-top'
V:| - (0) - [UIInputSetContainerView: 0x7fbf99668ce0]


...没有。



所以我从可以推断,窗口调整其约束以考虑添加的通话中状态栏,但UIInputWindowController不会。因此,约束冲突会产生。



但是情节变粗......



在初始约束冲突导致从呼叫中状态栏切换,约束不会改变,优先级相同,但进一步切换呼入状态栏进入或退出时不会出现约束冲突。 但是,这只是因为最初的冲突已经被抛出。



希望这会有所帮助!干杯。



感谢所有原始贡献者。


Just like this question: Auto Layout and in-call status bar and this question: Resize for in-call status bar?, I am having issues with the In Call Status Bar screwing up my view layout.

Here is my nested structure. I have a Custom Modal ViewController that is nested within another ViewController. Whenever the In Call Status Bar is shown (and then closed out of), this is what happens:

Here is a picture of what it should look like before the In Call Status Bar is shown:

The background blue color of the status bar after the bug occurs is the background color of the root view controller.

Whenever an In Call Status Bar is shown, the following error is printed out:

Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7fdac6192320 V:|-(20)-[UIInputSetContainerView:0x7fdac6190a40]   (Names: '|':UITextEffectsWindow:0x7fdac6061a10 )>",
    "<NSLayoutConstraint:0x7fdac608ebb0 'UIInputWindowController-top' V:|-(0)-[UIInputSetContainerView:0x7fdac6190a40]   (Names: '|':UITextEffectsWindow:0x7fdac6061a10 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7fdac6192320 V:|-(20)-[UIInputSetContainerView:0x7fdac6190a40]   (Names: '|':UITextEffectsWindow:0x7fdac6061a10 )>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7fc60b03d230 V:|-(20)-[UIInputSetContainerView:0x7fc608d22020]   (Names: '|':UITextEffectsWindow:0x7fc60b171720 )>",
    "<NSLayoutConstraint:0x7fc60b03d2d0 UIInputSetContainerView:0x7fc608d22020.bottom == UITextEffectsWindow:0x7fc60b171720.bottom>",
    "<NSLayoutConstraint:0x7fc60b17c4b0 'UIInputWindowController-height' UIInputSetContainerView:0x7fc608d22020.height == UITextEffectsWindow:0x7fc60b171720.height>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7fc60b03d2d0 UIInputSetContainerView:0x7fc608d22020.bottom == UITextEffectsWindow:0x7fc60b171720.bottom>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

Using FLEX debugging tool I can see that

UINavigationBarBackground and UIStatusBarForegroundView overlap before the In Call Status Bar, however afterwards UINavigationBarBackground is below UIStatusBarForegroundView.

This bug only occurs AFTER I present the Modal View Controller. If I show the In Call Status Bar, then the issue does not occur. You cannot go back to the root view controller after the Modal View Controller is shown.

What can I do to fix this?

解决方案

iOS 9.2.1, Xcode 7.2.1, ARC enabled

UPDATE 3/25/2016: Conflict still exists in Xcode 7.3, iOS 9.3.

Summary: In the window hierarchy for your application there are various windows that get added onto the application window. In my case, this was the UITextEffectsWindow and the UIRemoteKeyboardWindow. These windows come with preconfigured constraints. It seems there is a bug that updates some vertical layout constraints, but not other related constraints for the same window. This throws the constraints conflict in debugger. This happens when a custom window gets added to the window hierarchy or when the in-call status bar gets toggled in or out, on both the simulator and the actual iOS device.

The constraints are priority 1000, this indicates that they are required constraints.

The solution below will remove the conflicting constraint and add it back once the in-call status bar is toggled out.

EDIT 2/25/2016: Neither solution solves the problem of having the in-call status bar already displayed when opening app. The conflict happens before the change in status bar is registered.

It appears that this constraint conflict happens only the first time the in-call status bar is shown (this is most common), or in other scenarios involving the presentation of an additional custom window that would sit on top of the key window. I also tried just creating a blank single view application and with adding nothing toggling in the in-call status bar, and I got the same constraint conflict.

I think it is a bug and is discussed on the Dev forums. The original article from the Dev forums can be found here (as matty pointed out):

https://forums.developer.apple.com/thread/16375

I wanted to expand a little on matty's answer here. Which I found very helpful. I am not sure what impact removing "all" the constraints would cause, so I removed just the conflicting constraints. My reasoning being that the conflicting constraint will be broken anyway as the debugger informs "Will attempt to recover by breaking constraint"; so the constraint will serve no purpose anyway.

Here are the constraint conflict errors I was receiving:

After interpreting the constraint errors (see this apple document to help with that: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/DebuggingTricksandTips.html) I used the following code to get rid of the conflicting constraints:

Objective-C:

*AppDelegate.h

...

@interface YourAppName : UIResponder <UIApplicationDelegate>
{
    NSMutableDictionary *dictionaryConstraints;
}

...

*AppDelegate.m

...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.

    dictionaryConstraints = [[NSMutableDictionary alloc] init];

    return true;

}

- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
{
   NSLog(@"newStatusBarFrame: %@", NSStringFromCGRect(newStatusBarFrame));

   if (newStatusBarFrame.size.height > 20.0)
   {
        for (UIWindow *window in [[UIApplication sharedApplication] windows])
        {
            if ([window.class.description isEqual:@"UITextEffectsWindow"] || [window.class.description isEqual:@"UIRemoteKeyboardWindow"])
            {
                NSMutableArray *constraints = [[NSMutableArray alloc] initWithCapacity:[window.constraints count]];

                for (NSLayoutConstraint *constraint in window.constraints)
                {
                    if (!([constraint.description rangeOfString:@"V:|-(0)-[UIInputSetContainerView"].location == NSNotFound))
                    {
                        NSLog(@"");
                        NSLog(@"%@: %@, %f, %f", window.class.description, constraint.description, constraint.priority, constraint.constant);
                        NSLog(@"");

                        [constraints addObject:constraint];
                        [window removeConstraint:constraint];
                    }
                    else
                    {
                        nil;
                    }
                }

                if ([constraints count] > 0)
                {
                    [dictionaryConstraints setObject:constraints forKey:[NSString stringWithFormat:@"%p", window]];
                }
                else
                {
                    nil;
                }
            }
            else
            {
                nil;
            }
        }
    }
    else
    {
        nil;
    }
}

- (void)resetConstraints
{
    for (UIWindow *window in [[UIApplication sharedApplication] windows])
    {
        if ([window.class.description isEqual:@"UITextEffectsWindow"] || [window.class.description isEqual:@"UIRemoteKeyboardWindow"])
        {
            if (dictionaryConstraints)
            {
                NSArray *keys = [dictionaryConstraints allKeys];

                for (int i = 0; i < [keys count]; i++)
                {
                    if ([[NSString stringWithFormat:@"%p", window] isEqualToString:keys[i]])
                    {
                        [window addConstraints:[dictionaryConstraints objectForKey:keys[i]]];
                    }
                    else
                    {
                        nil;
                    }
                }
            }
            else
            {
                nil;
            }
        }
        else
        {
            nil;
        }
    }
}

- (void)application:(UIApplication *)application didChangeStatusBarFrame:(CGRect)oldStatusBarFrame
{
    NSLog(@"oldStatusBarFrame: %@", NSStringFromCGRect(oldStatusBarFrame));

    if (oldStatusBarFrame.size.height > 20.0)
    {
        if ([dictionaryConstraints count] > 0)
        {
            [self resetConstraints];
            [dictionaryConstraints removeAllObjects];
        }
        else
        {
            nil;
        }
    }
    else
    {
        nil;
    }

    for (UIWindow *window in [[UIApplication sharedApplication] windows])
    {
        if ([window.class.description isEqual:@"UITextEffectsWindow"] || [window.class.description isEqual:@"UIRemoteKeyboardWindow"])
        {
            for (NSLayoutConstraint *constraint in window.constraints)
            {
                if (!([constraint.description rangeOfString:@"V:|-(0)-[UIInputSetContainerView"].location == NSNotFound))
                {
                    NSLog(@"");
                    NSLog(@"%@: %@, %f, %f", window.class.description, constraint.description, constraint.priority, constraint.constant);
                    NSLog(@"");
                }
                else
                {
                    nil;
                }

            }
        }
        else
        {
            nil;
        }
    }
}

...

Swift:

*AppDelegate.swift

...

var dictionaryConstraints = [NSString : NSArray]();

...

func application(application: UIApplication, willChangeStatusBarFrame newStatusBarFrame: CGRect)
{
    print("newStatusBarFrame: \(newStatusBarFrame)")

    if newStatusBarFrame.size.height > 20.0
    {
        for window in UIApplication.sharedApplication().windows
        {
            if ((window.classForCoder.description() == "UITextEffectsWindow") || (window.classForCoder.description() == "UIRemoteKeyboardWindow"))
            {
                var constraints = [NSLayoutConstraint]()

                for constraint in window.constraints
                {
                    if (constraint.description.containsString("V:|-(0)-[UIInputSetContainerView"))
                    {
                        print("\(window.classForCoder.debugDescription), \(constraint.description), \(constraint.priority), \(constraint.constant)")

                        constraints.append(constraint)
                        window.removeConstraint(constraint)
                    }
                    else
                    {
                        //nil
                    }
                }

                if (constraints.count > 0)
                {
                    dictionaryConstraints[NSString(format: "%p", unsafeAddressOf(window))] = constraints
                }
                else
                {
                    //nil
                }
            }
            else
            {
                //nil
            }
        }
    }
    else
    {
        //nil
    }
}

func resetConstraints()
{
    for window in UIApplication.sharedApplication().windows
    {
        if ((window.classForCoder.description() == "UITextEffectsWindow") || (window.classForCoder.description() == "UIRemoteKeyboardWindow"))
        {
            if (dictionaryConstraints.count > 0)
            {
                let keys = Array(dictionaryConstraints.keys)

                for i in 0 ..< keys.count
                {
                    if (NSString(format: "%p", unsafeAddressOf(window)) == keys[i])
                    {
                        window.addConstraints(dictionaryConstraints[keys[i]] as! [NSLayoutConstraint])
                    }
                    else
                    {
                        //nil
                    }
                }
            }
            else
            {
                //nil
            }
        }
        else
        {
            //nil
        }
    }
}

func application(application: UIApplication, didChangeStatusBarFrame oldStatusBarFrame: CGRect)
{
    print("oldStatusBarFrame: \(oldStatusBarFrame)")

    if (oldStatusBarFrame.size.height > 20.0)
    {
        if (dictionaryConstraints.count > 0)
        {
            self.resetConstraints()
            dictionaryConstraints.removeAll()
        }
        else
        {
            //nil
        }
    }
    else
    {
        //nil
    }

    for window in UIApplication.sharedApplication().windows
    {
        if ((window.classForCoder.description() == "UITextEffectsWindow") || (window.classForCoder.description() == "UIRemoteKeyboardWindow"))
        {
            for constraint in window.constraints
            {
                if (constraint.description.containsString("V:|-(0)-[UIInputSetContainerView"))
                {
                    print("\(window.classForCoder.debugDescription), \(constraint.description), \(constraint.priority), \(constraint.constant)")
                }
                else
                {
                    //nil
                }
            }
        }
        else
        {
            //nil
        }
    }
}

...

Note: This keeps all constraints that are not conflicting. And adds the removed conflicting constraints back in after the conflicting situation is no more, namely the in-call status bar is toggled out.

UPDATE 2/25/2015: Further testing...

I decided to isolate the changing constraints using two methods in the app. delegate *.m file:

...

- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
{
    NSLog(@"New status bar frame: %@", NSStringFromCGRect(newStatusBarFrame));

    for (UIWindow *window in [[UIApplication sharedApplication] windows])
    {
        NSLog(@"%@, %@", window.description, window.constraints);
    }
}

- (void)application:(UIApplication *)application didChangeStatusBarFrame:(CGRect)oldStatusBarFrame
{
    NSLog(@"Old status bar frame: %@", NSStringFromCGRect(oldStatusBarFrame));

    for (UIWindow *window in [[UIApplication sharedApplication] windows])
    {
        NSLog(@"%@, %@", window.description, window.constraints);
    }
}

...

When the in-call status bar toggles in, the conflicting constraints change from:

UITextEffectsWindow:

< UITextEffectsWindow: 0x7fbf994cc810; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; layer = < UIWindowLayer: 0x7fbf994c8470> >,

( "< NSLayoutConstraint:0x7fbf99667eb0 V:|-(0)-[UIInputSetContainerView:0x7fbf99668ce0] (Names: '|':UITextEffectsWindow:0x7fbf994cc810 )>",

...omitted

"< NSLayoutConstraint:0x7fbf9966c800 'UIInputWindowController-top' V:|-(0)-[UIInputSetContainerView:0x7fbf99668ce0] (Names: '|':UITextEffectsWindow:0x7fbf994cc810 ) >",

...omitted )

UIRemoteKeyboardWindow:

< UIRemoteKeyboardWindow: 0x7fbf994ceb80; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; layer = < UIWindowLayer: 0x7fbf994cf190> >,

( "< NSLayoutConstraint:0x7fbf994cfb20 V:|-(0)-[UIInputSetContainerView:0x7fbf99744ec0] (Names: '|':UIRemoteKeyboardWindow:0x7fbf994ceb80 ) >",

...omitted

"< NSLayoutConstraint:0x7fbf9966c800 'UIInputWindowController-top' V:|-(0)-[UIInputSetContainerView:0x7fbf99668ce0] (Names: '|':UITextEffectsWindow:0x7fbf994cc810 )>",

...omitted )

...and changes to:

UITextEffectsWindow:

< UITextEffectsWindow: 0x7fbf994cc810; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; layer = < UIWindowLayer: 0x7fbf994c8470> >,

( "< NSLayoutConstraint:0x7fbf99667eb0 V:|-(20)-[UIInputSetContainerView:0x7fbf99668ce0] (Names: '|':UITextEffectsWindow:0x7fbf994cc810 )>",

...omitted

"< NSLayoutConstraint:0x7fbf9966c800 'UIInputWindowController-top' V:|-(0)-[UIInputSetContainerView:0x7fbf99668ce0] (Names: '|':UITextEffectsWindow:0x7fbf994cc810 ) >",

...omitted )

UIRemoteKeyboardWindow:

< UIRemoteKeyboardWindow: 0x7fbf994ceb80; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; layer = < UIWindowLayer: 0x7fbf994cf190> >,

( "< NSLayoutConstraint:0x7fbf994cfb20 V:|-(20)-[UIInputSetContainerView:0x7fbf99744ec0] (Names: '|':UIRemoteKeyboardWindow:0x7fbf994ceb80 ) >",

...omitted

"< NSLayoutConstraint:0x7fbf9966c800 'UIInputWindowController-top' V:|-(0)-[UIInputSetContainerView:0x7fbf99668ce0] (Names: '|':UITextEffectsWindow:0x7fbf994cc810 )>",

...omitted )

To understand the visual formatting language read https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/VisualFormatLanguage.html

It appears that the vertical layout constraints in the format "Vertical Layout V:[topField]-XX-[bottomField]" changes from...

NSLayoutConstraint:0x7fbf99667eb0 V:|-(0)-[UIInputSetContainerView:0x7fbf99668ce0]

to...

NSLayoutConstraint:0x7fbf99667eb0 V:|-(20)-[UIInputSetContainerView:0x7fbf99668ce0]

...for both windows: UITextEffectsWindow and UIRemoteKeyboardWindow; however, ...

NSLayoutConstraint:0x7fbf9966c800 'UIInputWindowController-top' V:|-(0)-[UIInputSetContainerView:0x7fbf99668ce0]

...does not.

So from what I can deduce, the window adjusts its constraint to account for the added in-call status bar, but the UIInputWindowController does not. Therefore, the constraint conflict arrises.

But the plot thickens...

After the initial constraints conflict resulting from the in-calls status bar toggling, the constraints do not change, and the priority is the same, but the constraints conflict does not arise with further toggling of the in-call status bar in or out. But, this just because the initial conflict was already thrown.

Hope this helps! Cheers.

Thanks to all the original contributors.

这篇关于在通话状态栏中(无法满足约束条件)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆