I'm developing an iOS application in Xcode 8. I'm having trouble getting my head around the auto-layout constraints even after reading various tutorials. I am trying to find what combination of constraints allows me to have an adjustable spacing between the top layout guide and the top of my image view.
Below is the preview of the view on iPhone 7 Plus:
iPhone 7 Plus Demo
The top constraint of the UIImageView is currently set to =50, which is the perfect size for larger screens. However, I am trying to have this spacing shrink on smaller screens, as seen below:
iPhone 4s Demo
I have tried what feels like all possible combinations of various constraints with different sizes and priorities but the spacing is either small on all screens or large on all screens. Is there something I am missing?
You can specify different constraint for different trait.
You can do it like below
override var traitCollection: UITraitCollection {
let trait = super.traitCollection
if view.bounds.size.height < 500 {
return UITraitCollection(verticalSizeClass: UIUserInterfaceSizeClass.compact)
}
return trait
}
Override trait collection
Select constraint
Select + button before constant field for the constraint in the inspector
Select height as compact and width as any
It will create another constant field for this constraint.
Specify lower constant value
Else you can make that constraint an outlet and in code, check if view.bounds.size.height < some_value than use smaller value as constant for the constraint else regular value
You can change the top spacing proportional to the height by taking the outlet of the topConstraint and in the viewDidLoad method you can change its value. . Here you need to find a constant value which when multiplied with the actual height of the device gives the required top spacing. Say you need 50p in 7+ which has a screen size of 736p so the constant is 50/736 = 0.067. So in 4s the spacing can be 480 * 0.067 = 33.
You can do this like
topspace.constant = self.view.frame.size.height * 0.067
After some playing around with the above ideas, I found a solution to my problem that lets me see the changes in the storyboard. I position my UIImageView in the preferred location (on iPhone 7+) and set an vertical alignment constraint at the current canvas value - I then set this constraint to have a priority of 750.
I then add a top constraint to the top layout guide which is greater than or equal to 10, this has a priority of 1000.
When seen on a larger screen, the UIImageView positions towards the vertical alignment. When seen on the smaller screens, the vertical alignment pushes the image to the top but the higher priority top constraint of 10 keeps it on the screen.
Related
I am designing one of my view in my
MainView
I am plan to have a smaller View instance in my MainView. What I need to do is:
When the app is running on iPhone, the view size should be square and its width is equal to the screen's with. When the app is running on iPad, the width should be 1/3 of the screen's width.
So how to define different width ratio on iPhone and iPad. How to approach this? Can I do this in storyboard file or I have to do this by code? Thanks in advance.
In your storyboard file you will need to create variations for traits. There is a button in the lower right hand side of the storyboard inspector that says "Vary for Traits", using this you can set constraints to have different constant values depending on the device size(iPad/iPhone).
In this case you can pin the leading and trailing edges of the smaller view to the sides of the parent view, and for the iPhone vary the trait to be equal to zero, while the iPads space can be set to 10 points(however many points of space you want).
Creating adaptive UI's can be and is a rather complex subject, so if you have no experience, like #Zack Leonidas Hamblen said check out that article and read up to get a better understanding on what is happening and how to use it efficiently.
You can set your constraints in Storyboard, create an #IBOutlet for the constraint and do something like:
if UIDevice.current.userInterfaceIdiom == .pad {
// set the width constraint = 1/3 of the screen width
} else {
// set constraint = screen width
}
I am attempting to vary my auto layout constraint by iPhone version. The vary for traits allows you to differ by size classes. However all the iPhones in portrait orientation are all compact width and regular height.
Assuming I have an element that is horizontally centered but I want my distance from the top of my main view to vary based upon device size, how should I accomplish this?
You cannot specify screen-sizes or device versions in auto-layout - only size classes.
If relative positioning/sizing doesn't work for you, and you want to do positioning such as 5 pts on iPhone SE and 15 pts on iPhone 6, you have to do it via code. Your options are:
Don't use auto-layout...
Change constraint values (constants, multipliers, priorities, etc)
If you read through Apple's docs on auto-layout, you can see it is targeted toward adaptive interface design, not alternate interface design.
Method 1 : Programmatically changing Constraint Values
If you want to set different constant top values for iPhone variation, then create a outlet of Top Constraint and change its constant value.
_topConstraint.constant = Conditional code for each device.
Method 2 : Setting Adaptive Constraints
Eg: I have taken a view with fixed height = 100, width = 200 and centred it horizontally.
Now it give a proportionate top space as per the device size, please gear up for some maths.
Suppose, the top space in iPhone5 screen = 36 pt.
Total View Height = view top + view height = 36 + 100 = 136
Total Screen Height = 568 Bottom Ratio = 568/136 = 4.17
So, set a bottom layout constraint and add the multiplier as 4.17.
enter image description here
On iPhone 7 plus and other devices, it changes the top automatically.
I have a tableView with static cells. The cell contains an ImageView which fills it completely. And I have another smaller ImageViews atop. I position this ImageViews with constraints. I have a question about resizing the constraints.
How can I set different constraint constants for different devices sizes without programming if/else loops. Is there a way to set it in the storyboard? I have a leading constraint to parent layout for example with an constant value of 10. This is okay for the iPhone 5 screen, but on an iPhone 6/ 6 plus screen it should be higher than 10.
iPhone5 Autolayout
iPhone6 Autolayout
Very easy. You can change constants values for difference size classes in Storyboard. I am giving u a few steps after which you will be able to grasp it.
First we create constants as you can see on this view
Next we select the constant we want to change the value in other size classes.
Now comes the tricky part. In the attribute inspector after selecting the constant, you can see the value of the constant. Right beside you can see the PLUS (+) sign, left of the "constant".
Click on it and select your size class that you want.
Here i have selected Regular Height Regular Width i.e for iPad sizes.
Next we give it a new value. So the constant, which normally is of value 61, will function as 10 when rendered in a size class of iPad size classes.
Here is the output --
iPhone 4:
iPad Air:
As you can see, the same constants has different value in runtime corresponding to different size classes.
Hope my explanation helped you.
Without writing a single line of Code!
Once my junior developer asked me the same question that how can I differentiate between iPhoneSE and iPhone6 for some constraint at that time there was only one solution that was writing some thing like
if device == iPhoneSE {
constant = 44
} else if device == iPhone6 {
constant = 52
}
To overcome this issue I created a library Layout Helper so now you can update constraint for each device without writing a single line of code.
Step 1
Assign the NSLayoutHelper to your constraint
Step 2
Update the constraint for the device you want
Step 3
Run the app and see the MAGIC
Finally, I`ve found the solution which works in my case.
I put the transparent view and added Align Center X/Y to Superview(background image) with the needed offset in the way which it suits my frame for posters(on the background image)- Constraints for the transparent view
Then I attach Equal width/height to my Superview(background image) for that transparent view and change multiplier in equal width(manually I picked 0.61)
After that, I landed my 1 poster. I also centered both vertically and horizontally with offset and used this set of constraints- Proportional width to Superview, Aspect ratio.
And the last I disposed my second poster with this constraints- Leading space to Poster1, Align CenterY to Poster1(with the offset in my case) and Equal width/height. Constraints for the Poster 1/2
As the result, I have really adaptive Autolayout which works almost great on iPhones 5-6-6+
You can use BayKit for this job.
What is BayKit:
Calculates the global offset for all screen sizes by depending on given screen size and given offset.
How to use BayKit:
Usage is very easy, just import BayKit and set constant value with BayKit like this:
import BayKit
class MyViewController: UIViewController {
lazy var box = UIView()
let magicOffset = BayKit()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(box)
box.translatesAutoresizingMaskIntoConstraints = false
box.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: magicOffset.offseter(scaleFactor: 1.0,
offset: 24, direction: .horizontal, currentDeviceBound: BayKit.DeviceList.iPhone5.screenWidth)).isActive = true
}
}
As you can see this line calculating offset for all screen sizes:
magicOffset.offseter(scaleFactor: 1.0, offset: 24, direction: .horizontal, currentDeviceBound: BayKit.DeviceList.iPhone5.screenWidth)
Offseter Features:
scaleFactor: You can set if you want bigger or smaller then given offset(for default set 1.0).
offset: Preferred constant in tested device.
direction: Which direction are you looking for,i.e. (for width, leading, trailing use .horizontal,for height, top, bottom use .vertical)
currentDeviceBound: Find your best fit device and set as a main device with this. BayKit will calculate constraints with depending on your best fit screen!
Example Result:
I want my app to run on every device fine.I have text field on the screen.I am giving constraints to text field as follows:
Aspect ratio to self
Aspect ratio to parent view
I this case my text field will scale according to screen size.Now issue is when i use this method then all my textfields look too big on iPad.I have seen facebook app on which TextFileds don't look too big.I look decent so please tell me what method should i use for this purpose.I know i can use size classes but i don't want to use size classes in my project.
Solution i want if a textField is on iPhone 4s is 20px then on iPad it should be 24px with out using aspect ratio & size classes concept.
Without Size classes You can achieve this using the following constraints. I have tested it on only one textfield and it is in center of screen. So overall constraints on this textfield is as follow:
Align center X to SuperView
Align center Y to SuperView
Width >= 168
Trailing Space to Superview Equals 270(approx) (priority = 999)
Leading space to Superview Equals 270(approx) (Priority = 999)
Height Equals : 30
What happen here is that On ipad 270 leading and trailing will be satisfied while on iphone having less width so both of these constraints shrink and width >= 68 constraints come in action. The result is show in pictures
IPHONE
IPAD
For my 1) portrait only 2) deployment target iOS7/iOS8 app, I have in my design UIButtons which have variable heights, for iPhone 5, iPhone 6 and iPhone 6+. I am trying to use auto layout for this. (Not using size classes though).
Using auto layout how can I specify variable height for UIButton for these 3 screen sizes. The buttons look fine on iPhones 5* models, but thinner on iphone 6/6+. Now in auto layout I can say height >= or = or <= say 55), but how do I specify 44 for iphone5, 55 for iphone6, 66 for iphone6+?
Is this something that I can achieve using only auto layout or do I need to manupulate (frames) it in code? What is the point of me using auto layout then?
In addition to frames my designs also specify different font sizes. How do I go about this. Any best known methods for this, Stack-O friends .. ??
You are correct to ask "what is the point of auto-layout if I have to manipulate frames directly"? Thankfully, you don't have to.
An easy way of doing it is specifying the height in relation to a view of standard height (think a view that fits the whole screen).
For example, we can set our button's height to equal half the height of the view.
This way, the button is always going to scale with the view, either upwards or downwards (size-wise). Auto-layout will guarantee that the relation between them will always be 1/2.
Now the button will be half the size of its superview, regardless of size.
It sounds like you need to be modifying the height constraints constant value.
In your xib/storyboard, create an outlet to your view/controller for the height constraint.
At runtime, probably in viewDidLoad, you will work out which device you're on, and then just change the constant of the height constraint.
CGFloat height;
// if iPhone 5
// height = 44
// else..........
self.buttonHeightConstraint.constant = height;
This will automatically trigger a flag that tells AutoLayout to recalculate frames and layout the view again.
I managed this by adding a Height-Constraint to the UIButton. Make an Outlet and you can set the Height in your UIViewController subclass with _myConstraint.constant = 55;