I need to set translatesAutoresizingMaskIntoConstraints to NO. By default it is set to YES (to assist with the majority of apps that are transitioning from struts and springs to the new Auto Layout).
Is there somewhere in Xcode where the default can be changed from YES to NO?
Or do I have to manually set it for every view?
I'm late to this question, but the mentioned option is still missing in Xcode 5 & 6, so the question is still meaningful.
Actually, we can always set a value to any property of a view/control/object by adding a User Defined Runtime Atribute in Storyboard (Interface Builder) like the following screenshot.
And it also works for translatesAutoresizingMaskIntoConstraints. So the question could be solved.
This is a great question - and one I've tried to find an answer to myself. Sadly, it looks like there is no "quick fix". Currently, Apple considers Constraint-based layout Opt-in - even naming a section of the UIView Class Reference:
Opting in to Constraint-Based Layout
But that Opt-in is not global. I presume this is because not everything looks good if you just turn Springs & Struts into Constraints. Some UI elements break, or you would get a ton of unsatisfiable constraints errors.
I can think of one possible solution - I have not tried it myself, but you could make a category on UIView that sets all UIView objects to return NO for - (BOOL)translatesAutoresizingMaskIntoConstraints. While I do not know what this would break, it would globally set translatesAutoresizingMaskIntoConstraints to NO.
Here is a good introduction to Categories if you want to learn more about them!
When u have to change the size or position of your subview. Use (BOOL)translatesAutoresizingMaskIntoConstraints method before you set the frame of your subview.
[self.benchmarkButton removeFromSuperview];
[self.benchmarkButton setTranslatesAutoresizingMaskIntoConstraints:YES];
[self.benchmarkButton setFrame:CGRectMake(20, self.benchmarkButton.frame.origin.y+40, 260, 30)];
[self.benchmarksView addSubview:self.benchmarkButton];
Thats way your subview will not fight from constraints as it is default (AutoLayout) in Xcode 4.3 and later. Thanks
According to the documentation, this property is automatically set to NO if the view is added through Interface Builder.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instp/UIView/translatesAutoresizingMaskIntoConstraints
Related
I want to practice creating simple apps using no storyboard. I am able to do the constraints programmatically (slowly) but I want to also practice separating my code into MVC. Is there a particular place/method that I am supposed to write the programatic constraints? Or does it not matter?
Good discussion in the comments. My thoughts, based on that discussion?
With an understanding that the question is subjective, you place your constraints:
The earliest in a view controller's life cycle where they work.
As "close" to the view as possible.
If it's something common, make it as universal as possible.
Understand how your specifics fit into everything.
(Understand, the question isn't limited to constraints. It could apply to hierarchies, UI, even database tables when you get down to it!)
Sticking to constraints, and my answer....
(1) Use the UIViewController and UIView lifecycles.
Generally the view life cycle is loadView, viewDidLoad, viewWillAppear, viewWillLayoutSubviews, viewDidLayoutSubviews, and viewDidAppear. great SO answer detailing this.
I believe that loadView is too early for constraints, but not viewDidLoad - **provided you aren't expecting to know the frame size. While many say viewDidLayoutSubviews is the right place for that, I've found that viewWillLayoutSubviews most times works just as well. Either way, get your constraints set as soon as possible!
(2) Do it as close to the view as possible.
If you have subviews - I have a "ToolBar" class of objects - you want the constraints, at least as much as possible, to be coded inside the class. For instance, in my tool bar, it slides out, has buttons, and even rotates upon orientation. The only constraints not inside these classes is for orientation - that owner is (and I believe should be) the view controller instantiating it.
(3) Make it universal.
I plan to use this tool bar across a few apps. So the first thing I did was add it to a framework. This framework was needed because I had an app that I delivered a photo editing exension - and the "edit" screen is as much the same as possible. In the end I move all my constraints there. (At least as much as possible.) Anything that I believe is reusable.
(4) Understand the specific requirements of your app.
This should be obvious. If you need to code for various orientations, use arrays and activate/deactivate them. (YES, a common mistake is replacing them! That's setting yourself up for some major headaches.)
If you can keep things active, declare the constraint, set `isActive = true1, and forget about it. If you need to adjust that constraint's constant or multiplier, in the declaration name it and then where you need to alter it, do it.
My conclusion? Auto layout is a very useful tool - more so in code. But the placement of code is like asking "how does one code an OOP app for auto rentals" or " how does one design a database for auto rentals". It not just an art, there are many answers. These are the "rules" I try to follow - YMMV.
To get started with this style of development I recommend checking out Let's Build That App as he goes through very in-depth examples of setting up complex apps entirely in code, without storyboards.
The way he structures the constraints is using a custom implementation of UIView, that way your view code is separated from the ViewController. Then, in the viewDidLoad method you can instantiate your implementation of UIView with something like self.view = MyView().
I wrote a few apps like this. The major drawbacks are that it can become very difficult to make quick adjustments, and you really need to learn about all the different types of constraints you can use.
Here's a pastebin of some extensions I used when doing this. I hope this helps.
Trying to implement support for Dynamic Type and have an issue. I set the style I want to use on a label or something in Interface Builder. I register for the UIContentSizeCategoryDidChangeNotification, and in the handler, I set the label's font to ... what? How do I know what style to use? Shouldn't there be an accessor that lets me find that out? If not, I have to put it in 2 places, which means they'll get out of sync and I'll be annoyed. Any thoughts?
I don’t think this will satisfy you, but set the font to [UIFont preferredFontForTextStyle:UIFontTextStyleTitle2 or whatever style you set in Interface Builder.
Ignore the setting in Interface Builder. It’s not even worth setting. Interface Builder is a (mostly) static representation of the initial state of your views, but this is Dynamic Type.
You could subclass UILabel to make it dynamic, and/or join us on the dark side of setting up views in code.
Since iOS 10, there's no need to follow this rationale because the adjustsFontForContentSizeCategory property allows an automatic scaling of the font sizes according to the content type size selected in the settings.
All the text styles are well defined in the Apple reference site and their size variations as well.
Since I've seen many other IOS projects written in obj-C, I found that many of them do not use interface builder or storyboard file. It's hard to see what's going on. And I've known that loadview method should do the things similarly to drag and drop objects in IB. So what is the difference between loadview method and doing some dragging objects in interface builder?
Well, you don't have AutoLayout (unless you use hard code to constraints too) and Size Classes without interface builder.
Working with IB is much less coding and more clarity.
If you add a Label to IB then the IB is responsible to release that object. And it's added to the view of course so you don't have to.
I would never go without IB now and would recommend to do so for other devs.
I use Size Classes + AutoLayout and all my screens looks good on every device plus that iOS9 is coming out: I have multiple screens auto enabled because I used Size Classes. App works without maintenance for many years..
Simple difference between IB and loadView
IB:
All u can do is drag and drop things without having any code written.
loadView:
It is first viewCycle method which calls on loading any view of corresponding viewcotroller, You should do all your stuff programmatically here. like adding subviews to your view. and adding constraints etc.
Thanks
In my apps I'm working a lot with constraints, in most cases with animations as well. In certain circumstances I need to remove constraints and add new ones.
As I need to support iOS 7 as well, I'm not able to use the active property, which would else be the solution for me.
The way to remove constraints is to use the removeConstraint method on a UIView.
Is it possible to create a method like
constraint.remove()
so you don't have to know which view is taking care over the constraint?
What I do is create arrays of the constraints that I wish to be able to add/remove and simply use the following:
#property NSMutableArray *newConstraints;
Fill up the newConstraints
iOS7 and iOS8:
[self.viewToChange addConstraints:self.newConstraints];
[self.viewToChange removeConstraints:self.newConstraints];
or iOS8 only, use the new mechanism
[NSLayoutConstraint activateConstraints:self.newConstraints];
[NSLayoutConstraint deactivateConstraints:self.newConstraints];
With this you can apply a set, remove the set and apply a new set.
You can also create the initial list from the storyboard set if you can identify which constraints are which.
I've ended up using the method autoRemove provided by the PureLayout library: https://github.com/smileyborg/PureLayout
This method finds the commonSuperview using the firstItem or secondItem and removes the constraint from the correct view.
It resulted in this one liner:
containerTopConstraint.autoRemove()
No, not that I'm aware of. The automatic managing of the host view only came in iOS8.
An ugly implementation could loop over all constraints of all views to finde the view where it is on.
But normally it shouldn't be to hard to manage the constrains in a way that you always know on which view they are defined.
Layout for Apple Watch is based on placing objects to storyboard. Every new object is placed just under the previous one etc. There is also possible to use groups and align objects same way horizontally. (see details here) I would appreciate to have the same functionality on iOS - to place UIViews this way and define them same attributes like alignment, width relative to container etc. just like in WatchKit.
It is also similar with LinearLayout on Android. I found CSLinearLayoutView on github, but its very old and it doesn't use autolayout.
Does any good library for this purpose exist?
If not.. It looks very easy to implement this by myself, do you see any key problems or limitations which would make it impossible?
I don't think there is or will be any addon for the Interface Builder itself, so you could use the same (ugly watchkit) constraints for iOS apps. AutoLayout for iOS is way better and more flexible to use than that WatchKit mess inside IB (Interface Builder of Xcode).
I do prefer to do most of the design work in my code so I don't have to worry if the IB will create some unnecessary stuff for me. If you want some drag and drop, you should use use IB and learn how to use AutoLayout.
The interesting part:
If you want to create your design in code and want some library which is easy to use, you can try on of these: Masonry (Obj-C) or SnapKit (Same Lib but in Swift). Both libs are very strong and up to date. I don't know if the dev implemented a custom alignment to center a subview in its superview. You should check that by yourself. :) If you like the VFL (Visual Format Language), like I do. You should search for a similar Lib or wait until I'm done with my project some day. :D I was inspired by SnapKits shiny syntax and started creating my own framework for VFL constraints. I also implemented the possibility to center my subview in its superview.
let spacer1 = View(name: "spacer1")
let spacer2 = View(name: "spacer2")
let view1 = AutoLayoutView(name: "view1")
view1.backgroundColor = UIColor.whiteColor()
view1.layer.cornerRadius = 50
let view2 = AutoLayoutView(name: "view2")
view2.backgroundColor = UIColor.redColor()
view2.layer.cornerRadius = 10
self.rootView.addSubview(spacer1)
self.rootView.addSubview(spacer2)
self.rootView.addSubview(view1)
self.rootView.addSubview(view2)
self.rootView.addConstraints { (add) -> Void in
add.group({ (add) -> Void in
add.normal.vertical.format("[view1(100)]").alignCenterHorizontaly
add.normal.vertical.format("[view2(30)]")
add.normal.horizontal.format("[view1(100)][spacer1]").alignCenterVerticaly
add.normal.horizontal.format("[spacer1][view2(40)]").alignCenterY
add.normal.horizontal.format("[view2][spacer2(==spacer1)]|")
}, identifier: "GroupName")
}
And with this we we get something like that:
There is still a lot work to do, so I can't public unfinished work yet.
I hope I could help you a little. :)
Introduced in iOS 9 as UIStackView - https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIStackView_Class_Reference/
Custom UIStackView implementation for iOS 7+
https://github.com/oarrabi/OAStackView