Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice for modifying storyboard auto layout constraints in code?

I've always done my UIs in code but have decided that I should use storyboards and auto layout for a current project. Everything had been going well until I built a complex scene with about 50 views with lots of hierarchy and some grid of views.

The problem is that my auto layout is getting muddled on some devices and orientations. I'm finding it challenging to use IB to try fixing the dozens (hundreds?) of constraints or to track down the problems and resolve them. The situation is such that I'm not getting errors or warnings, just some unpleasant layouts at times. And IB can be a pain with all the clicking and changing settings you need to do to track down constraint information, let alone get a full idea of how they all relate in a scene.

I've just spent a day reading docs and background material on auto layout and constraints and it seems my best solution is to use the visual format to specify constraints in code and create some custom code to help. However, I can't seem to find anything on how to make the transition from IB to code.

Specifically, should I wipe all IB constraints and do them all by hand or is it possible to be selective? I ask because I have some groups of views in containing views where the content views have a perfect layout.

Secondly, where best do I put my code? I want to coexist storyboards and just want to selectively modify some complex scenes. Is a view controller's viewWillAppear: the right place to modify or remove/add constraints for the view it controls?

like image 997
Fran K. Avatar asked Dec 05 '22 08:12

Fran K.


2 Answers

Connect an IBOutlet for the NSLayoutConstraint you want to be able to modify in the storyboard/xib file to your controller/view class.

Once you have the layout object connected, you can modify the .constant property and animate the view:

[self.containerView layoutIfNeeded]; //make sure all layout operations are done
self.containerViewBottomLayoutConstraint.constant = 200.0; //change the layout
[UIView animateWithDuration:duration animations:^{
    [self.containerView layoutIfNeeded]; //animate the changes
}];

updated: you can add your modification code in viewDidLoad, awakeFromNib, viewDidAppear, or event based. It really depends on your intentions.

like image 72
Ron Avatar answered May 30 '23 13:05

Ron


Sorry to take so so long to get back to this while other projects intruded.

I had to do a lot of refactoring to simplify my scenes so that auto layout could do the right thing, and yet I am not fully satisfied with the results. The problem seems to be that IB is just not easy to use with lots of items, and that auto layout is complicated, by necessity.

With that said, the best results I've seen so far are drawn from this article by Justin Driscoll: http://themainthread.com/blog/2014/02/building-a-universal-app.html

He advocates building custom views to encapsulate reusable UI components. I have taken this approach but have extended the idea to also bundle up related components that are not going to layout very differently as the layout changes. For example, I have a progress bar with button and two labels, so even though I am not reusing them as a group, they need to be adjacent and conceptually are related, so I've made a custom view for them which handles the auto layout as Justin suggests.

I'm now taking the approach that each level of auto layout should only have a handful of elements. If one level gets too complex, I'll bundle up some related items in a custom view and push some auto layout inside that new view. So far it isn't too bad.

like image 31
Fran K. Avatar answered May 30 '23 13:05

Fran K.