Solving Storyboard missing trailing/leading constraints warning - ios

I'm shipping my app for all iPhone models (iOS 10.0+) and have made sure that in all localisations, labels and controls will not overlap.
In a simple static cell, it would be enough to give the label on the left side a leading constraint and center it vertically. The same would be done with the control on the right, but with a trailing constraint. All would be fine.
Until Xcode warning.
It asks for missing trailing or leading constraints to avoid overlapping in any case (which would not happen in mine).
Here is a simple test case:
I silenced the warning by giving a switch on the right a leading constraint of 10.0, just to make sure. It works fine. (Attached image first row)
The same, however, with a segmented control would stretch it all the way to the left to the right side of the label. Attached image 3rd row) Even if I increased the size of the label further to the right it would stomp the width of the label.
Since I'd like to have the cell as in the 2nd row, I did what I considered hacky in the view controller, in which case I'd have to specify exact x values for each screen size (which is ok, but I'd like to avoid) (Storyboards, after all...):
#IBOutlet weak var mySegmentedControl: UISegmentedControl!
override func viewWillLayoutSubviews() {
mySegmentedControl.frame = CGRect(x: 238.0, y: mySegmentedControl.frame.minY,
width: 121.0, height: mySegmentedControl.frame.height)
}
Is there a better way to achieve this?

New versions of Xcode will show this as a warning.
You could fix this Adding greater than or Equal constraint to UILabel's trailing.
NB: you can quick fix by clicking on the Yellow Right Arrow near the My Table View Controller Scene text
The UILabel is variable in length. When you set text to label, it will resize automatically. If you are not setting the Trailing Constraint it may overlaps other views (in this case - segmented control). It will work if you add fixed constraint, but new Xcode shows it as warning. So we have to change it as greater or lesser than constraints.

Related

How to make the text on UILabel appear on the top-left corner after adding constraints?

I'm developing an iOS application that has a Segue where some information is displayed. The information that I'm displaying is appearing in the middle of the Segue and I want it to appear right below the X or close button.
I added the constraints necessary in the Storyboard and in the Storyboard I see it as I want it, but it's not translating when the application is ran. The text where I'm having problems can be seen in the picture below in the right, which is the Segue.
The following code snippet is meant to make the text start from the top left corner of the label text.
override func viewDidLoad() {
super.viewDidLoad()
infoLabel.text = text
infoLabel.numberOfLines = 0;
infoLabel.sizeToFit()
}
but after adding some constraints on that label to make it adapt to other screen sizes the text stopped starting on the top-left corner and started right in the middle-left corner. How can I fix this?
If you want to make label to constrain to right, don't give the leading constraint. Just the trailing, top constraints are enough for a label. Only give width constraint if you want label to take a fixed space.
In your case, just delete the leading constraint.
You can also play with the text alignment, set the text alignment to right if you want to keep your constraints intact.
You need to align the text and set to right alignment

Design UIView so that it can dynamically change its height based on the content height

In a XIB file I have a CustomView related to a class with the same name.
The view content is quite simple.
There are a vertical stackview and inside the stackview there are two labels. The stackview is vertically aligned to the view that contains it:
The first label (title) contains a static text (always a few characters).
The second label (subtitle) can have variable length text.
I add this CustomView with other similar views as a subview of a Content View, as it was a “row”.
for i in 0...aViews.count {
var v = CustomView(frame: CGRect(x: 0, y: _y, width: 320, height: 100))
v.labelText = "my long label text ..."
contentView.addSubview(v)
// ...
}
As you can imagine, the title label should have a fixed position (top and left), that is, there cannot be a row with the title starting at 10 points and another at 14.
I must admit I naively thought the position of the label would have been automatically managed by the same fact that I aligned vertically the stackview. I was wrong and I noticed no problem at all, until they told me the second label, the subtitle, could contain more than one line.
I added lines to the label directly in the storyboard, and found out that:
the container of the stackview doesn’t change its height based on the height of its content;
the position of the “fixed” elements is maybe vertically centered but not fixed;
What I need is the following:
the labels should be “grouped” and aligned vertically: there should be the same amount of space from the top of the first label to the upper border of the container and from the bottom of the second label to the bottom border;
when the second label has to display more than one line, the container view should change its height accordingly;
Is this possible? How should I design my view?
OK - looking at your project, you're not far off... just a couple key items.
In your CustomView.xib, you had no constraint between Fixed Label and Date Label. The result is that the Date Label grows up from the bottom of the view, with nothing to stop it.
Also in your CustomView.xib, you had the Fixed Label constrained to the trailing edge... I assume you want it left-aligned with Date Label
When creating your CustomViews, you were setting a height constraint of 100 -- which defeats the purpose of allowing the content to determine the size.
In CustomView class, you had contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] commented out. That line should be there.
In your view controller, you added a height constraint to contentView with a low priority. Best option is to make that a Placeholder constraint (double-click the constraint, and select the Placeholder checkbox). That way the constraint is removed at run-time, but is there during design (and Storyboard doesn't complain).
You were doing a few other un-necessary things - likely you were trying different stuff to get it to work.
The view setup (adding your views) is best done in viewDidLoad() -- definitely not in viewDidLayoutSubviews()
I'm guessing that, in your CustomView, instead of an explicit width of 200 you probably want to constrain the Date Label leading and trailing, allowing it to horizontally stretch based on the device width... but I left it at 200.
If you can follow that information, you should be able to fix the issue(s). But, I put the project up as a GitHub repo for you, so you can get it in a "working" state, and so you can see the changes.
Here's the link to the repo: https://github.com/DonMag/ATester2
Here is the result:
And scrolled up a bit:
I think you are mixing absolute positioning of outer views (i.e. manually setting frames) and using autolayout constraints for their inner components, and wrongly expect the dynamic autolayout part to somehow "reach all the way up" to the outer views. For autolayout to do that, you'll need to use autolayout all the way up, including the way CustomViews are positioned in your contentView.
If for whatever reason you do not want to use a TableView or CollectionView for this you could also, for example, try adding your CustomViews as arranged subviews to a vertical stackview that has top/bottom/leading/trailing constraints to contentView, then replace the "Align Center Y" constraint of your CustomView with "Align Top" and "Align Bottom" constraints to actually allow your labels to "push" from the inside if they need more vertical space.
Edit here's a quick sketch to illustrate that setup:
Edit 2 here are a couple of screenshots to clarify further. With a basic layout like this:
the result will look like this at runtime:
Note that the UIStackViews use the "Equal Spacing" Distribution in this example. If you want to create and add your CustomViews programmatically, use the StackView's func addArrangedSubview(_ view: UIView).
Good luck!

Swift - Why ScrollView not full screen?

I had inserted a ScrollView into UIViewController and dragged ScrollView to fill the space between the navigation bar and the RAM label below:
But when I run the app, the ScrollView does not fill the space:
Please help me! Thank you very much.
P/S: Sorry for my english is bad.
The scroll view is not covering up the whole thing because you are running the app on a much bigger phone. The simplest solution is to run the app on iPhone 5.
However, if you want to solve the problem on all sizes of iOS device, you need to add constraints.
Constraints are things that tells a view when and how much it should resize and where it should be positioned.
To add a constraint, just select the view you wish to add a constraint to and go to the bottom right corner. You will see 4 buttons:
The leftmost button is used to embedding views in stack views. This is a feature of iOS 9. If your deployment target is lower, just ignore it.
The second button to the left is for adding constraints related to alignment - where the edges of the views are, what its baseline is and where it is positioned in the X and Y axes:
The third button to the left is used to add constraint related to margins, width, height and how the width and height should change when it is asked to resize (keep the aspect ratio, for example):
The rightmost button is used to let Xcode decide what constraints you should add. And I think most of the times its choices are okay. Sometimes though, you still need to do some tweaking before it works.
"So... what constraints should I add?" you asked.
Well, I think I should teach you how to think when you want to add a constraint. This way, you can figure it out yourself in the future.
You should first let Xcode guess what constraints you want. Just click the rightmost button and click "Reset to Suggested Constraints". This can save a lot of work if Xcode can get it right. So remember to always do this first.
Then, run your app on various devices and see if the view's position, size, and alignment are as you expected. If it is not, you might have to add and/or remove some constraints.
For example, if you found that your view is always the same size on different devices, (that could be bad because it means that some content my go out of view on smaller devices) it's probably because Xcode added a width and/or height constraint to the view. You should delete that so that the view's width and/or height is not fixed.
You can find your view's constraints in the view hierarchy:
Just select the constraint and press delete.
Uncheck Adjust subview option and add
scrollview.view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
You need to add constraints for your scrollView. Set the leading and trailing constraints to 0. Pin the height of your scrollView and also don't forget to set the top layout constraint. You can either pin the height or add bottom layout constraint to your page control.
Constraints are very important and its even more important to set it correctly. Check the Apple Documentation - Working with constraints in IB
Uncheck constrain to margins and add 0 every one of the four limits of spacing to nearest neighbour.
My guess (from the little information we have) is that you are creating a constraint from your scrollview to the top of your view with a value equal to the height of the navigation bar. Set the value of this constraint to 0.
Just set the 4 constraints to 0 to the area you need and then uncheck the "Content Layout Guides" checkbox in the constraints tab here. It will automatically adjust to the area you have specified.
The checkbox to uncheck

Inconsistent Today Widget behavior breaks subview's height constraints

This question is related to another question I just posted on Stackoverflow:
Layout Constraint Conflicts in Default Today Widget
I added a Today Extension as a target to my app, removed the default "Hello World" label that's inside the widget's root view and added a plain UIView in its place. I gave the view a yellow color and pinned it to all edges of the root view - the same way the label was constrained. Then I added another constraint to the yellow view in order to give it a fixed height of 100px.
When I launch the app (tested on simulator and device) that height constraint is simply ignored and the yellow view takes up the whole available space all the way down to the header of the next widget.
When I swipe the notification center up and pull it down again the view suddenly jumps (it seems like it's suddenly "seeing" its own height constraint) leaving a vertical blank space of 39px at the bottom of the widget:
 
I figured that the 39px margin at the bottom is the default bottom margin of a today widget as passed in by the defaultMarginInsets parameter in the widgetMarginInsetsForProposedMarginInsets(defaultMarginInsets: UIEdgeInsets) method and that I can fix this inconsistent behavior by overriding this method and providing my own margin insets:
func widgetMarginInsetsForProposedMarginInsets(defaultMarginInsets: UIEdgeInsets) -> UIEdgeInsets {
var newInsets = defaultMarginInsets
newInsets.bottom = 20
return newInsets
}
However, I would really prefer to use system provided margins instead of fixed values. It seems to me like this is another iOS bug regarding the today widget. Is it? And if not: How can I fix this?
Try avoiding the use of pins.
For positioning, rely on aligning your view to the superview's leading, trailing, top, or bottom edges.
For sizing, try setting your view to have equal heights or widths with the superview. And adjusting the multiplier as needed.
This solved auto layout inconsistencies I was experiencing in a Today Widget.
Updated w/ screenshot:
See above, I am using the align menu (not the pin menu). I select both the view I am trying to constrain, along with the all encasing superview, and tell the prior to share (or, align with) trailing and bottom edges.
I know this is not how Apple may demonstrate it, however it is a workaround that avoids the bugs that occur when using pins with Today Widgets.
Update #2 - And here is all the constraints (including height and width):
The bug must be related to the inferred sizing of a view that is entirely pinned, because when I set the height and width of my view to be relative to its superview (rather than having it be inferred), the bug does not occur.

Xcode IB auto sizing?

Everything looks fine in IB. When I run my app using an iPhone5/iPhone6/iPad sims, it's completely mangled.
In IB:
In iPhone6 sim:
In the above sim, the buttons are cut. The textfield and textview are also cut. For the TF & TV, they are aligned center but trail off the edges on both sides.
I have the buttons width set
Editor > Pin > Widths Equally
The title label is set with a
Horizontal Center in Container
constraint
The textfield and textview also have
Horizontal Center in Container
and
Editor > Pin > Width
Is there some way to fix this?
-- EDIT --
After a few tries with constraints, looks like I have everything working except the two buttons.
Current listing of constraints:
As suggested by others, you should consider using the Auto-layout feature if you plan on constructing your views using the IB.
Here are some tutorial links:
RayWenderlich.com Part One
Youtube video This one covers a bit of size clases
Hope they help.
UPDATED:
I've read your updated post, you need to add width and height constraints. The view you see in the IB right now is 600 by 600 points, and the simulator one is smaller, which means that if you leave it as is, when you run the app you'll only see what the iphone screen has the capacity to show.
You need to add more constraints than what you used, try defining an equal width for the buttons, and assign the left one a left margin constraint, the right one a right margin constraint, give both of them vertical spacing constraint related to the text view or long label, the text view or long label should have left and right margin constraints, a height constraint and a top constraint to the textfield, the textfield should have a vertical spacing constraint to the label, also left and right and height constraint, and last the label should have leff, right and height constraints plus a top constraint to the main view.
I feel that those are all you need, but Xcode will through warnings at you if it feels you are missing something.
Try it, and let us know.

Resources