gpt4 book ai didi

ios - 在通话状态栏中(无法满足约束条件)

转载 作者:行者123 更新时间:2023-12-02 07:51:05 26 4
gpt4 key购买 nike

就像这个问题:Auto Layout and in-call status bar和这个问题:Resize for in-call status bar?一样,我在“通话中状态栏”出现问题时搞砸了我的 View 布局。

这是我的嵌套结构。我有一个嵌套在另一个ViewController中的自定义模态ViewController。每当显示“通话中状态栏”(然后关闭)时,就会发生这种情况:

enter image description here

这是显示“呼入状态”栏之前的外观的图片:

enter image description here

发生错误后状态栏的背景蓝色是根 View Controller 的背景颜色。

每当显示“呼入状态”栏时,都会打印出以下错误:

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.

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

通话中状态栏之前 UINavigationBarBackgroundUIStatusBarForegroundView重叠,但是之后 UINavigationBarBackgroundUIStatusBarForegroundView以下。

仅当我介绍了Modal View Controller之后,才会发生此错误。如果我显示“通话中状态栏”,则不会发生此问题。显示“模态视图 Controller ”后,您将无法返回到根 View Controller 。

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

最佳答案

iOS 9.2.1,Xcode 7.2.1,启用ARC的

更新2016年3月25日:冲突在Xcode 7.3,iOS 9.3中仍然存在。

摘要:在您的应用程序的窗口层次结构中,有各种窗口被添加到应用程序窗口中。在我的情况下,这是UITextEffectsWindowUIRemoteKeyboardWindow。这些窗口带有预配置的约束。似乎有一个错误会更新某些垂直布局约束,但不会更新同一窗口的其他相关约束。这在调试器中引发约束冲突。在模拟器和实际的iOS设备上,当自定义窗口被添加到窗口层次结构中或调用状态栏被切换为进出时,就会发生这种情况。

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

下面的解决方案将删除冲突的约束,并在拨入调用状态栏后将其重新添加。

编辑2016年2月25日:两种解决方案都无法解决打开应用程序时已显示通话状态栏的问题。在注册状态栏更改之前发生冲突。

似乎这种约束冲突仅在首次显示调用中状态栏时才发生(这是最常见的),或者在其他情况下(涉及位于键窗口顶部的其他自定义窗口的呈现)发生。 我也尝试仅创建一个空白的单 View 应用程序,并且在通话中状态栏中未添加任何切换,并且遇到了相同的约束冲突。

我认为这是一个错误,将在开发论坛中进行讨论。 Dev论坛的原始文章可以在这里找到(如matty指出的那样):

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

我想对matty's answer here进行扩展。我发现这很有帮助。我不确定删除“所有”约束会产生什么影响,因此我仅删除了冲突的约束。我的理由是,当调试器通知“将尝试通过打破约束进行恢复”时,无论如何冲突的约束都会被打破;因此,约束将毫无用处。

这是我收到的约束冲突错误:

enter image description here

enter image description here

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

目标-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;
}
}
}

...

雨燕:

* 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
}
}
}

...

注意:这将保留所有不冲突的约束。并在不再出现冲突情况后将已删除的冲突约束重新添加回去,即调用中状态栏被移出。

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

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

- (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);
}
}

...

当通话中状态栏切换时,冲突的约束将从以下方式更改:

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 )



...并更改为:

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 )



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

似乎格式为“垂直布局V:[topField] -XX- [bottomField]”的垂直布局约束已从...更改。

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



到...

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



...对于两个窗口:UITextEffectsWindow和UIRemoteKeyboardWindow;然而, ...

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



...才不是。

因此,从我可以推断出的角度来看,窗口会调整其约束条件以说明已添加的通话中状态栏,但UIInputWindowController却没有。因此,约束冲突到来。

但是情节变厚了...

在由调用状态栏切换引起的初始约束冲突之后,约束没有改变,并且优先级相同,但是在进一步切换调用状态栏的状态时,不会发生约束冲突。 但是,这仅仅是因为最初的冲突已经引发。

希望这可以帮助!干杯。

感谢所有原始贡献者。

关于ios - 在通话状态栏中(无法满足约束条件),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33112762/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com