iOS 8 键盘扩展:出现呼叫栏时出现约束错误?

Posted

技术标签:

【中文标题】iOS 8 键盘扩展:出现呼叫栏时出现约束错误?【英文标题】:iOS 8 Keyboard Extension: Constraint Error When Call Bar Appears? 【发布时间】:2014-11-10 21:24:31 【问题描述】:

我注意到,当我在打电话时,绿色的通话栏出现在屏幕顶部,我的自定义键盘不会出现(就好像它被跳过了一样)。于是调试了一下,发现是约束错误。

这是调试器中的错误:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The layout constraints still need update after sending -updateViewConstraints to <KeyboardViewController: 0x16dfbe30>.
KeyboardViewController or one of its superclasses may have overridden -updateViewConstraints without calling super or sending -updateConstraints to the view. Or, something may have dirtied layout constraints in the middle of updating them.  Both are programming errors.'
*** First throw call stack:
(0x2ab43c1f 0x382eec8b 0x2ab43b65 0x2e6300ef 0x2b7cb5b9 0x2e630203 0x2e0ef4e9 0x2b7cb5b9 0x2e0ef2c3 0x2e630487 0x2e29ba8b 0x2e0004d7 0x2da28a0d 0x2da243e5 0x2da2426d 0x2da23c51 0x2da23a55 0x2dff8965 0x2ab0a3b5 0x2ab07a73 0x2ab07e7b 0x2aa56211 0x2aa56023 0x31e4f0a9 0x2e0621d1 0x389cf9fb 0x389d1021 0x2b916635 0x33956065 0x33955d3b 0x33956099 0x37c7a4fd 0x3886eaaf)
libc++abi.dylib: terminating with uncaught exception of type NSException

请务必注意,在没有呼叫栏的情况下,无论是方向还是方向更改,我都不会收到任何错误/警告。我正在使用以下方法将键盘的高度从 216 调整到 270:

- (id)initWithCoder:(NSCoder *)aDecoder 

    if (self = [super initWithCoder:aDecoder]) 

        //Prepare our keyboard's values
        self.portraitHeight = 270;
        self.landscapeHeight = 190;
    

    return self;


- (void)updateViewConstraints 

    //Super
    [super updateViewConstraints];

    //Check if self.view exists
    if (WIDTH(self.view) == 0 || HEIGHT(self.view) == 0) return;

    //Remove any previous constraints
    [self.inputView removeConstraint:self.heightConstraint];

    //Define landscape mode
    self.isLandscape = !(self.view.frame.size.width == ([[UIScreen mainScreen] bounds].size.width * ([[UIScreen mainScreen] bounds].size.width < [[UIScreen mainScreen] bounds].size.height)) + ([[UIScreen mainScreen] bounds].size.height *([[UIScreen mainScreen] bounds].size.width > [[UIScreen mainScreen] bounds].size.height)));

    //Update view height depending on orientation
    if (self.isLandscape) 
        //Readjust our keyboard's height
        self.heightConstraint.constant = self.landscapeHeight;
        [self.inputView addConstraint:self.heightConstraint];
        self.view.frame = CGRectMake(0, 0, WIDTH(self.view), HEIGHT(self.view));
     else 
        //Re-adjust our keyboard's height
        self.heightConstraint.constant = self.portraitHeight;
        self.heightConstraint.priority = 990;
        [self.inputView addConstraint:self.heightConstraint];
        self.view.frame = CGRectMake(0, 0, WIDTH(self.view), HEIGHT(self.view));
    

&这是我的观点WillAppear:

- (void)viewWillAppear:(BOOL)animated 

    //Update our keyboard's height when view appears
    self.heightConstraint = [NSLayoutConstraint constraintWithItem:self.view
                                                         attribute:NSLayoutAttributeHeight
                                                         relatedBy:NSLayoutRelationEqual
                                                            toItem:nil
                                                         attribute:NSLayoutAttributeNotAnAttribute
                                                        multiplier:0.0
                                                          constant:self.portraitHeight];
    self.heightConstraint.priority = 990;
    [self.view addConstraint:self.heightConstraint];

** 注意:WIDTH() 和 HEIGHT() 是宏。

我在我的 xib 中使用自动布局。我不知道从哪里开始解决这个问题。

更新

感谢您帮助调试此@Remus!我现在正在尝试检测设备何时在我的 ios 8 扩展程序中旋转,但我的 updateConstraints 方法仍未被调用。

- (void)viewDidLayoutSubviews 

    [super viewDidLayoutSubviews];
    [self.view setNeedsLayout];
    [self.view updateConstraintsIfNeeded];
    //I've also tried [self.view updateConstraints]; instead


- (void)updateConstraints 

    NSLog(@"Check Width");
    //Check if self.view exists
    if (WIDTH(self.view) == 0 || HEIGHT(self.view) == 0) return;

    NSLog(@"Remove Old Constraints");
    //Remove any previous constraints
    [self.inputView removeConstraint:self.heightConstraint];

    NSLog(@"Define Landscape");
    //Define landscape mode
    self.isLandscape = !(self.view.frame.size.width == ([[UIScreen mainScreen] bounds].size.width * ([[UIScreen mainScreen] bounds].size.width < [[UIScreen mainScreen] bounds].size.height)) + ([[UIScreen mainScreen] bounds].size.height *([[UIScreen mainScreen] bounds].size.width > [[UIScreen mainScreen] bounds].size.height)));

    NSLog(@"Update view height depending on orientation.");
    //Update view height depending on orientation
    if (self.isLandscape) 
        //Readjust our keyboard's height
        self.heightConstraint.constant = self.landscapeHeight;
        [self.inputView addConstraint:self.heightConstraint];
        self.view.frame = CGRectMake(0, 0, WIDTH(self.view), HEIGHT(self.view));
     else 
        NSLog(@"Detected in portrait.");
        //Re-adjust our keyboard's height
        self.heightConstraint.constant = self.portraitHeight;
        self.heightConstraint.priority = 990;
        [self.inputView addConstraint:self.heightConstraint];
        self.view.frame = CGRectMake(0, 0, WIDTH(self.view), HEIGHT(self.view));
    


- (void)viewWillAppear:(BOOL)animated 

    NSLog(@"View Did Appear: Add Constraint.");
    [self.view updateConstraints];

    //Update our keyboard's height when view appears
    self.heightConstraint = [NSLayoutConstraint constraintWithItem:self.view
                                                         attribute:NSLayoutAttributeHeight
                                                         relatedBy:NSLayoutRelationEqual
                                                            toItem:nil
                                                         attribute:NSLayoutAttributeNotAnAttribute
                                                        multiplier:0.0
                                                          constant:self.portraitHeight];
    self.heightConstraint.priority = 990;
    [self.view addConstraint:self.heightConstraint];

【问题讨论】:

我认为您覆盖 updateViewConstraints 的方式肯定有问题。您是否在该方法中放置了断点以找出实际触发约束失败的行? 糟糕!好主意,让我们试试吧! 好的,这很奇怪。所以显然updateViewConstraints 被调用了 3 次。在第一次通过时,它假定默认高度为 216,在第二次通过时,它调整所有内容,在第三次通过时,它加载最后一行(即使它在第二次空间中分配了空间)。奇怪的是,当我设置断点时,一切正常。所以也许这与时间有关?也许顶栏的约束会干扰我键盘上的默认约束? 可能.. 如果您尝试在 updateConstraints 而不是 updateViewConstraints 中调用这些函数会怎样? 感谢 Remus,但我似乎找不到 updateConstraints 的方法调用。嗯... 【参考方案1】:

让我们尝试调用viewDidLayoutSubviews 中的函数。这也可以在任何其他约束事件(如updateViewConstraints 等)中单独调用。

- (void)viewDidLayoutSubviews 

    [super viewDidLayoutSubviews];
    [self setKeyboardConstraints];


- (void)setKeyboardConstraints 

    NSLog(@"Check Width");
    //Check if self.view exists
    if (WIDTH(self.view) == 0 || HEIGHT(self.view) == 0) return;

    NSLog(@"Remove Old Constraints");
    //Remove any previous constraints
    [self.inputView removeConstraint:self.heightConstraint];

    NSLog(@"Define Landscape");
    //Define landscape mode
    self.isLandscape = !(self.view.frame.size.width == ([[UIScreen mainScreen] bounds].size.width * ([[UIScreen mainScreen] bounds].size.width < [[UIScreen mainScreen] bounds].size.height)) + ([[UIScreen mainScreen] bounds].size.height *([[UIScreen mainScreen] bounds].size.width > [[UIScreen mainScreen] bounds].size.height)));

    NSLog(@"Update view height depending on orientation.");
    //Update view height depending on orientation
    if (self.isLandscape) 
        //Readjust our keyboard's height
        self.heightConstraint.constant = self.landscapeHeight;
        [self.inputView addConstraint:self.heightConstraint];
        self.view.frame = CGRectMake(0, 0, WIDTH(self.view), HEIGHT(self.view));
     else 
        NSLog(@"Detected in portrait.");
        //Re-adjust our keyboard's height
        self.heightConstraint.constant = self.portraitHeight;
        self.heightConstraint.priority = 990;
        [self.inputView addConstraint:self.heightConstraint];
        self.view.frame = CGRectMake(0, 0, WIDTH(self.view), HEIGHT(self.view));
    

【讨论】:

感谢您的帮助莱姆斯!所以我尝试了以下方法(更新了我的答案)但根本没有调用该方法(现在我只是使用 NSLogs 来查看它是否被调用)但我什么也没得到。 嗯.. 用viewDidLayoutSubviews 调用它怎么样? 好的,所以现在它似乎正在记录(首次加载时为 3x,方向切换时为 1x。谢谢!但 updateConstraints 方法没有被更新。只是为了确保我们调用 [super .self.view updateConstraints] 或 [self.view updateConstraints] 在 updateConstraints 方法中? 您不想在其自身内部调用 updateConstraints - 这将开始一个无限循环。您应该在特定事件或触发器中调用一次[self.view updateConstraints](如键盘出现、viewWillAppear 或旋转)。 哦,对了,我想我期待一个类似于super 的调用,就像我在updateViewConstraints 中使用的那样。我还有最后一期。我似乎无法让updateConstraints 开火。我更新了上面的答案,以更清楚地说明我的方法是什么样的。非常感谢您的耐心等待!

以上是关于iOS 8 键盘扩展:出现呼叫栏时出现约束错误?的主要内容,如果未能解决你的问题,请参考以下文章

当我在 iOS7 中使用物理键盘在 UITextfield 上键入时出现错误

win10系统在安装卸载SVN时出现2502错误代码的问题

执行全新安装 Piranha CMS 时出现外键约束错误

在 mysql 表上添加外键约束时出现错误 1005

有外键约束的子表插入数据时出现的错误

SQLSTATE [HY000] Laravel 8 中的外键约束格式错误