11

I have a simple UIInputViewController subclass with only two overridden methods. I use this input view controller as inputAccessoryViewController on my UIViewController subclass which becomes first responder. I try to specify height of inputView by adding constraint as Apple documentation recommends. Problem is that my constraint doesn't work and I get autolayout exception when my constraint is being added

Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
...
(
    "<NSLayoutConstraint:0x178aa1d0 V:[UIInputView:0x178a4ae0(0)]>",
    "<NSLayoutConstraint:0x178b9520 V:[UIInputView:0x178a4ae0(500)]>"
)
Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x178b9520 V:[UIInputView:0x178a4ae0(500)]>

Which I think means that system already added a zero height constraint to the input view (because it is created with zero height). Now they conflict and autolayout breaks my constraint to fix the issue.

When I try to use it as inputViewController of my view controller (just for test purposes), I get same exception but instead of zero height it is 216 px. It also breaks my constraint and the height remains default.

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    self.inputView.translatesAutoresizingMaskIntoConstraints = NO;
    self.inputView.backgroundColor = [UIColor redColor];
}

- (void)updateViewConstraints {

    CGFloat _expandedHeight = 500;
    NSLayoutConstraint *_heightConstraint = 
    [NSLayoutConstraint constraintWithItem:self.view
                                 attribute:NSLayoutAttributeHeight
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:nil
                                 attribute:NSLayoutAttributeNotAnAttribute
                                 multiplier:0.0
                                   constant: _expandedHeight];
    [self.inputView addConstraint: _heightConstraint];

    [super updateViewConstraints];
}

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self.view setNeedsUpdateConstraints];
}

As a result, I am not able to change input accessory view height. Has anyone succeed in it? Obviously, Apple documentation provides no help...

Carlos Jiménez
  • 527
  • 5
  • 15
hybridcattt
  • 3,001
  • 20
  • 37
  • V:[self(0)] is very strange – who added this constraint? Obviously, it needs to be fixed or at least removed. – user3125367 Oct 02 '14 at 13:44
  • May be a hacky solution, but in updateConstraints find that 0/216 constraint (actually all constraints on just height, except yours) and set it's priority to lower value, for it to be skipped silently on conflicts. – user3125367 Oct 02 '14 at 13:48
  • @user3125367 "who added this constraint?" - exact question I'm looking an answer for :) I'll try your suggestion and post later, thanks! – hybridcattt Oct 02 '14 at 13:54
  • Try subclassing your view, overriding `addConstraint:` and see who calls it. Post the stack trace here. – Léo Natan Oct 03 '14 at 18:52
  • @LeoNatan addConstraint is called only with my constraint. No previous calls to my view... I assume it gets added to some superview of the inputView. I'm stuck at the same point – hybridcattt Oct 06 '14 at 14:08
  • overriding addConstraint seems to only catch constraints added by user, not system generated ones. It seems that whatever was used as height for the frame on initialize is added as a constraint somewhere. – moger777 Nov 08 '14 at 23:23

4 Answers4

12

Since iOS 9.0 this can be solved with inputView.allowsSelfSizing = YES;

pronebird
  • 12,068
  • 5
  • 54
  • 82
  • 1
    I just wanted to thank you for this answer. It took me half a day to find it with my humble search skills. It is exactly what solved the problem for me even in iOS 16. – alobaili Oct 07 '22 at 21:58
3

I don't know if this is the issue, but the problem may come from the 0.0 multiplier you are setting on _heightConstraint. Try to change it to 1.0.

It would look like this:

NSLayoutConstraint *_heightConstraint = 
    [NSLayoutConstraint constraintWithItem:self.view
                                 attribute:NSLayoutAttributeHeight
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:nil
                                 attribute:NSLayoutAttributeNotAnAttribute
                                 multiplier:1.0
                                   constant: _expandedHeight];

Hope this helps!

cris
  • 323
  • 3
  • 10
1

When you make a view the input accessory view of a UITextView, as soon as the text view becomes first responder, a height constraint is added automatically set to whatever was sent as the frame height. For example:

let inputView = UIInputView(frame: CGRectMake(0, 0, view.bounds.width, 200), 
    inputViewStyle: .Default)
someTextView.inputAccessoryView = inputView
someTextView.becomeFirstResponder()
assert((inputView.constraints().last as NSLayoutConstraint).constant == 200)

You can modify this constraint after the fact.

matt
  • 515,959
  • 87
  • 875
  • 1,141
moger777
  • 1,117
  • 11
  • 16
  • note, only works if you don't have setTranslatesAutoresizingMaskIntoConstrants – moger777 Nov 10 '14 at 16:37
  • This should be the correct answer, works for me (so long as constraints are not being translated to autoresizing mask) – Joshua Feb 20 '15 at 15:28
  • It's about the inputAccessory view of UIInputViewController not the one of someTextView. I don't know why you are talking about that one... It's independent each other – LKM Aug 06 '16 at 16:25
0

I did it in Swift. hope this helps you.

override func viewDidAppear(animated: Bool) {

    let heightConstraint = NSLayoutConstraint(
        item:self.view,
        attribute:NSLayoutAttribute.Height,
        relatedBy:NSLayoutRelation.Equal,
        toItem:nil,
        attribute:NSLayoutAttribute.NotAnAttribute,
        multiplier:0.0,
        constant:100)

    self.view.addConstraint(heightConstraint)
}
satoshi
  • 1
  • 2