26

I had a similar problem to this poster. And I used jrturton's suggestion to move the code for customizing the buttons into viewDidLayoutSubviews. It was working well until I received this error:

'NSInternalInconsistencyException', reason: 'Auto Layout still required after sending -viewDidLayoutSubviews to the view controller. ViewController's implementation needs to send -layoutSubviews to the view to invoke auto layout.'

I'm very clueless on graphics, and the only thing I could think of was to put [self.view layoutSubviews]; but that didn't fix anything. It worked when I unchecked "Auto Layout" in my Storyboard, but that changed the dimensions of my buttons, and I was wondering if there was another way to fix it?

Code:

-(void)viewDidLayoutSubviews {
    NSArray *arrayOfButtons = [NSArray arrayWithObjects:self.decimalButton, self.buttonOne, self.buttonTwo, self.buttonThree, nil];

    for (UIButton *button in arrayOfButtons) {

        [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [button setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];

        button.layer.borderWidth = 0.25f;
        button.layer.borderColor = [[UIColor grayColor] CGColor];

        CAGradientLayer *btnGradient = [CAGradientLayer layer];
        btnGradient.frame = button.bounds;
        btnGradient.colors = [NSArray arrayWithObjects:
                              (id)[[UIColor colorWithRed:122.0f / 255.0f green:188.0f / 255.0f blue:255.0f / 255.0f alpha:1.0f] CGColor],
                              (id)[[UIColor colorWithRed:96.0f / 255.0f green:171.0f / 255.0f blue:248.0f / 255.0f alpha:1.0f] CGColor],
                              nil];
        [button.layer insertSublayer:btnGradient atIndex:0];
    }
}
Community
  • 1
  • 1
stumped
  • 3,235
  • 7
  • 43
  • 76
  • 1
    What about calling `[super viewDidLayoutSubviews]`? The docs say the default implementation does nothing, but worth a try. – Chris Wagner Mar 19 '13 at 04:02

1 Answers1

66

I had this issue recently, when I wanted to programmatically adjust frame of the view created by storyboard, by providing a viewDidLayoutSubviews message handler. Following the instruction from exception message, I tried to add [self.view layoutIfNeeded] at the end of -viewDidLayoutSubviews, and then it worked.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Hercrom
  • 684
  • 7
  • 3
  • 4
    I'm confused as to why this works. It seems like this should end in infinite recursion, but it doesn't. After calling `[self.view layoutSubviews]`, wouldn't `viewDidLayoutSubviews` get called again, and so on? – Snowman Nov 16 '13 at 18:06
  • 2
    My guess is that there are several passes during which time the auto layouts "settle", i.e. they are progressively marked as satisfied or not until no ambiguity remains. – Rupert Rawnsley Jan 10 '14 at 19:01
  • You saved me. I thought for sure the error indicated that we should explicitly call `layoutSubviews` *before* the call to the `super` implementation. – user Jun 29 '14 at 01:17
  • 21
    This works, though I called [self.view layoutIfNeeded] instead and that worked, too -- in the docs, it says never to call layoutSubviews directly. – Anna Dickinson Oct 27 '14 at 16:25
  • I guess there's a reason why you got so many votes on this one. We're all confused about how this works, and since cocoa touch is not open source, we can only guess. +1 to Hercrom for the fix. And +1 to @Anna Dickinson for pointing out a better fix. – HotFudgeSunday Jan 08 '15 at 20:09
  • [self.view layoutIfNeeded] should be better. But I am not sure if this fix has any side effect on iOS 8? – Wingzero Mar 04 '15 at 02:22
  • 6
    This seems to be fixed on iOS8, it also doesn't happen if you place the code into viewWillLayoutSubviews instead – aryaxt May 20 '15 at 21:49