iOS auto layout centering view with leading and tailing margin issue - ios

I have a subview that contains UIImageView and label where label can be changed dynamically. I set this subview on storyboard with auto layout align vertical center and top/bottom space. So when its label get changed, margin between image and label remains same and subview maintains its align to vertical center as it grows horizontally. But I also want to this subview not to change its width when it hits certain margin (leading and tailing space) respective to its superview. I tried to add auto layout programatically once it reaches to certain point but removing its layout once its get shirked didn't work (i.e. label didn't get change its width even though I called [label sizeToFit]). One thing that came up on my mind was set leading and tailing layout on storyboard and change its constant value properly as label size changes. I would like to know if there is better solution to solve this layout issue. Thanks

Related

dynamic height of of scrollview subviews in autolayout ios

I am creating a UIScrollView from xib, in which 3 view are there 2 UIViews and in middle an UIImageView. when I am setting constraints Xcode asked to set Y position constrains. But the problem is Y position constraint is blocking Scrollview to scroll down and automatically adjusting the views which looks ugly in landscape mode.
when I am delete that constraint it ask to fix height of subview. I searched a lot but I am new in autolayout so not understanding many of solutions. any help would be great.
You have to set all the height constraints in the content view.
But you also want the height of the Content to be proportional to the screen size.
To do this assign the height constraint of the imageview [equal|proportional|a-computation-of] to the view containing the UISCrollView.
It seems weird to skip levels of herarchy when assigning constraints between two views whose are not direct ancestor/sibling of each other but within a scrollview (at least) it is perfectly acceptable.
You are basically telling the scrollview that it's content has a known size and at same time setting this content to adapt dinamically to the screen size (if the constraints of the root uiview are set correctly)
UIView1
|---UIScrollView
|---UIView2
|---UIImageView [heightConstr.constant=UIView1.height-UIView2.height-UIView3.height-margins]
|---UIView3
This is the basic idea, to be done programmatically, then you can explore other solutions.
Unfortunately the constraint system in ios pretty much sucks when it's up to more complex equations involving more views for a single constraint.
UIScrollViewcan be tricky when adding constraints. You should always add a subView that will behave as the content view for your UIScrollView and all your subsequent views will go inside this content view.
UIView1
|---UIScrollView
|---UIContentView
|---UIView2
|---UIImageView
Set your UIScrollViewconstraints as you would normally but set your content view to have leading, trailing, top and bottom to the UIScrollView but also add two more constraints which will be equal width and equal height to the viewController.view but will have a low priority (So that whichever direction your content will increase in, that constraint will break and automatically increase the content size of the scroll view by taking in the inferred height of the content view). Now go on and add constraints on all your subview as you normally would. Which i'm assuming would be:
Your topmost view will have top and leading and trailing to its superView and also a fixed height.
Your bottom view will have leading, trailing and bottom to its superView and also a fixed height.
Your UIImageViewwill have a leading, trailing and top to top most view and bottom to the bottom view.
Edit:
Here is the screenshot just in case (To show the view hierarchy with the content view's constraints in the inspector)

How to use scrollview with subviews of a dynamic height?

I have a label inside a scrollview that has can be as few as 1 lines and as many as 10 lines. I'm having trouble figuring out how to make the scrollview content size dynamic so that it will stretch accordingly.
I tried adding a height constraint of >= 100 (arbitrary number) but then it complained about it being an Inequality Constraint Ambiguity.
Quick answer
Remove the current height constraint on your label.
Ensure the labels Lines property is set to 0 and Line Breaks is set to Word Wrap.
Add vertical spacing constraints to the views above and below the label.
Ensure that every view has vertical spacing constraints from the top to bottom margins, in order for the scroll view to infer the height of its contentView.
Explanation
In order for the scroll view to infer its content size it must have constraints from margin to subviews to margin - imagine it like a balloon the content is the air inside that pushes on the wall to make the balloon the size it is. The constraints from the subviews to margins allow the size of the subviews to push the walls of the content view out.
For the label setting the Lines property to 0 means it will have a variable amount of lines just as you want. The Line Breaks property being set to Word Wrap means it will ensure words are not cut off (truncated) or broken up into characters and instead pushed onto the next line as whole words.
If you don't specify a height constraint for a UILabel it will take a height that fits the whole text. Just make sure that number of lines is set to 0 and that your label has all the margin constraints set.
This tech note from Apple explains how to correctly configure a scrollview with scrollable content using auto layout only https://developer.apple.com/library/ios/technotes/tn2154/_index.html.
Conceptually, in your case, this is what you need to do:
View hierarchy:
MainView -> ScrollView -> ContentView -> UILabel
Scrollview is constrained to all edges of the main view,
ContentView is constrained to all edges of the ScrollView
and the UILabel is constrained to all edges of the ContentView (set UILabel number of lines to 0 and remove the height constraint you currently have applied)
The key here is to realise that the size of the contentView only depends on the size of the UILabel so as the UILabel height stretches so does the contentView. This will allow the scrollView to automatically infer the contentSize and enable scrolling if required.

Swift - UIScrollView Scrolls Partially

My problem is slightly different from other's 'Swift UIScrollView' problems when using auto layout:
Problem:
Unlike others, when I run my app, it scrolls. My problem is that the scroll cuts off the bottom 20-30% of the content. I can pull to see the buttons did build and are down there, but when I let it go the scroll snaps back to a false bottom which cuts off my content!!! I've been trying, for days, to fix it to scroll the entire height but it continues to cut off!!
Description of app:
I used auto layout to layout 6 buttons and labels. Each button a rectangular image, with a label directly beneath it. (sorry, the site won't let me post pictures!)
I have my views arranged like this:
MainView > ScrollView > ContentView > Buttons & Labels
I have my contentView pinned to my ScrollView and my ScrollView pinned to my MainView. My buttons and labels all have constraints that are building correctly, to create a list that looks like:
Rectangular button
Label beneath it
Spacing
Rectangular button
Label beneath it
Spacing
Etc.
Can anyone tell me why I can't scroll the full length of the view?
Your description of how your items are constrained is vague, so I'm going to list all of the constraints you need to make this work. Then you can compare what you have to what you need and adjust accordingly.
Your ScrollView should be pinned on all 4 sides to the MainView. (This isn't absolutely necessary. You can constrain your ScrollView however you want, but make sure it can grow as the device and/or orientation changes).
Your ContentView should be pinned on all 4 sides to the ScrollView with offsets of 0.
Since you want your ScrollView to scroll vertically only, constrain the width of the ContentView to the width of the ScrollView using an Equal Widths constraint. To do this, in the Document Outline view, Control-drag from your ContentView to your ScrollView and select Equal Widths from the pop up.
The height of ContentView will be set by the sum total height of everything in it. In order for this to work, your topmost button needs to be pinned to the top of the ContentView, all of your buttons and labels should be pinned to their nearest neighbors, and the bottommost label should be pinned to the bottom of the ContentView. In addition, all of your buttons and labels should have constraints for their widths and heights. I would suggest setting an explicit width constraint and explicit height constraint for your buttons and centering them horizontally in the ContentView. For your labels, set an explicit height constraint and pin the left and right edges to the ContentView.
If you have these constraints and no other ones, your ContentView will be properly sized.
Using contentView, like you said, usually fixes the issue. So chances are you need to take a second look at your contraints. Maybe try this solution in a clean/new project to see that it works. (it does work). My guess would be that some of your constraints conflict each other.
Otherwise I think it would be a good idea to setContentSize of your scrollView in your viewDidLoad.
Another hack would be to place 2 UI objects with their alphas set to zero on the right top corner and left bottom corner. This would hint scrollView to set its contentSize.

Correctly Size UILabel inside UIScrollView using Interface Builder and Autolayout?

I've created a simple view setup in interface builder. Here's how it looks:
The view hierarchy is simply:
view
- scrollView
-- label
The scroll view is shown with grey background anchored to its super view top, leading, trailing, and bottom with constraints of 0.
The label is shown with yellow background and has constraints as shown. Additionally, the label has content hugging priority of 1000 for both horizontal and vertical, and it has content compression resistance priority of 1000 for both horizontal and vertical.
In portrait orientation, the label is sized correctly:
In landscape orientation, however, the label is not sized correctly horizontally (I intended for the label to fill the width of the screen, less constraint insets as shown):
How can I get this label to size correctly horizontally in landscape orientation?
There is one solution for you.
1. Add your UIScrollView to container (UIView) with zero constraints:
2. Add constraints for Label: top, bottom, leading, trailing spaces = 20.
3. Add constraint: label.width = container.width - 40
For this, select label in the view structure tree, tap ctrl and pull
to container. And select Equal Widths.
Then select the created constraint and go to its Utilities and set
the constant value to 40.
You should get the following components:
Run the app, go to landscape and it works!
Hope it is clear. Best Regards.
It's hard to tell which constraint(s) to add/remove in order to get what you want because iOS reserve the right to adjust your constraints whenever it becomes impossible for it to satisfy all your constraints.
I make a blank project with the same view you have (UILabel as subview of UIScrollView) and make some constraints to get the UILabel resized properly on landscape.
A must check though:
Make sure you set the vertical/horizontal spacing constraints from the pin option, as shown below and try to remove unneeded constraints manually.

iOS Auto Layout >> View is not Changing its Size

I have a design for a screen that should look like this (other things will be added later, but I cannot seem to resolve the basis...):
I have added Constraints to determine the following:
Both Labels are Constraint in spacing to the screen edges.
Middle View is Horizontally and Vertically Constraint to the Middle of the Background View Center.
I have added 4 Constraints to express Minimum and Maximum Vertical Spacing between the Middle View and the Labels (Current spacing as Maximum and Standard spacing as Minimum).
I have also added 2 Constraints to the Middle View to define Spacings from the Screen right and left edges.
I thought that it should be enough, but in reality, when switching between Retina 3.5 and 4 the Bottom Label disappears and the Middle View is cut in the middle:
I have tried lowering the Middle View Content Hugging and Content Compression Priorities, and still no good.
Here are the Warnings I get:
Any idea how to resolve this?
Or alternatively, how to approach it differently (preferably, still using Auto Layout)?
Add Equal Width & Equal Height constraints as well & It will work
Add TopSpaceToContainer constraint for Top Label. Then add width and height constraints for your yellow view at the middle. Remove the multiple vertical spacing constraints given to the Top Label and Bottom Label.

Resources