Xcode 10, Swift 5 (this should be doable purely in the Storyboard)
The current layout:
- ChildView (child View of very first default view)
- ButtonView
- ScrollView
- VerticalStackView
- Button
- Button
- ...
- FooterView
- HorizontalStackView
- Button A
- Button B
What contraints do I need to always keep the Footer View at the bottom and make the UIStackView scroll behind it, while still maintaining a fixed height for each button in the UIStackView?
This setup seems to attract multiple problems, from the buttons inside not being clickable (or UITextFields that can't be interacted with), to the UIScrollView not being scrollable or a "Content Size Ambiguity" error (described here) - just because a single constraint isn't set properly.
The result:
If there are less buttons that can all be displayed at the same time, it won't be scrollable but instead simply display the black background below the last button.
How to get there:
The constraints are set using the "add new constraints" button below the preview window.
ChildView:
Trailing/Leading/Bottom: 0 to Superview
Equal Height: to Safe Area:
Control-drag from the ChildView to the Safe Area and pick "Equal Heights"
1. FooterView:
Trailing/Leading/Bottom: 0 to Superview
Height: Equals 50
Top to ButtonView:
Control-drag from the FooterView to the ButtonView
Choose "Top"
Click on the new constraint to open it in the inspector (FooterView.Top equals ButtonView.Bottom)
2. ButtonView:
Trailing/Leading/Top: 0 to Superview
Bottom to FooterView (already explained above)
2.1. ScrollView (black):
Trailing/Leading/Bottom/Top: 0 to Superview
The Bottom/Top constraints keep the ScrollView from "spilling over"
2.1.1. VerticalStackView:
Alignment/Distribution: Fill
Trailing/Leading/Bottom/Top: 0 to Superview
Equal width to ButtonView:
Control-drag from the VerticalStackView to the ButtonView and pick "Equal Widths"
This disables the horizontal scrollbar of the ScrollView
2.1.1.1. Button (gray):
Height: 50
The VerticalStackView takes care of the rest
Of course you can also replace the buttons in the 'UIScrollView' with views to create some type of form.
Related
I'm setting up content in a scroll view with autolayout. The objects in the scrollview are pinned top-to-bottom to the previous one, so that they are under one another. I have a footer view that is added at the end, below these objects.
Here's the catch: when there's few content, the contentView will be smaller than the screen height, so the footer view will appear somewhere in the middle of the screen (which is the normal behavior). But I'd like to prevent that, and make the view stay somewhere at the bottom.
In other words, I would like to setup a double constraint like:
Put this view below all the objects in the scrollview
AND
keep this view at a distance of max [some number] of the bottom of the screen
In a way that both constraints are always satisfied:
If the height of the content is bigger than the screen, then the view appears at the bottom, after scrolling down
If the height is smaller, then the view is "pinned" to the bottom of the screen, leaving a space relatively big between the bottom of the content and the top of this view
How can I achieve that with AutoLayout?
Fairly easy to do with Auto-Layout only... no code required.
The key is to use a "content view" to hold the elements, and a greater-than-or-equal constraint between your "bottom" element and your "footer" view.
In this image, yellow is the main view, green is the scroll view, blue is the content view, the labels are gray and the footer view is pink.
Start with a fresh view controller
add a scroll view, normal constraints (I used 20 all the way around, so we can see the frame)
add a UIView to the scrollView - this will be our "content view"
constrain contentView Top/Bottom/Leading/Trailing all equal to 0 to the scrollView
constrain both the Width and Height of the contentView equal to the scrollView
add your elements - here I used 3 labels
constrain the labels as usual... I used:
LabelA - Top/Leading/Trailing all at 20, vertical spacing to LabelB of 60
LabelB - Leading/Trailing at 20, vertical spacing to LabelC of 60
LabelC - Leading/Trailing at 20
LabelC is also set to Number of Lines: 0 so it will expand with multiple lines of text
Add a UIView as a "footer view" (I stuck a label in it)
constrain the footerView Leading/Trailing/Bottom all at 20 (so we can see the frame)
either set a Height constraint on footerView, or use its content to constrain its height
add a Vertical Spacing constraint from LabelC to footerView, and set it to >= 40
last step, change the Height constraint of contentView to Priority: 250
Now, as you expand/contract the height of LabelC, the footerView will keep at least 40-pts of vertical space. When LabelC gets big enough to "push" footerView below the bottom, scrollView will become scrollable.
Results:
you need to check ContentSize of scrollView and modify FooterView Top Constraint with the required Value
My class code
import UIKit
class scrollViewDrag: UIViewController
{
/// ScrollView Outlet
#IBOutlet weak var mainScrollView: UIScrollView!
/// Footer View top spacing constraint
#IBOutlet weak var footerViewTopConstraint: NSLayoutConstraint!
/// Used for ScrollView Height
var screenHeight = CGFloat()
/// Did Load
override func viewDidLoad() {
super.viewDidLoad()
}
/// Function used to check for height
func checkForHeight(){
/// Get scrollView Height
screenHeight = mainScrollView.frame.size.height
/// Check contentSize Height ?
if mainScrollView.contentSize.height >= screenHeight {
/// When ScrollView is having height greater than your scrollView Height
/// Footer will scroll along other Views
}
else{
/// Issue Case
let spacingValue = screenHeight-mainScrollView.contentSize.height
footerViewTopConstraint.constant = spacingValue
}
}
/// Call the height function in DidAppear
override func viewDidAppear(_ animated: Bool) {
checkForHeight()
}
}
Storyboard
I had used Four View with Equal Heights And at last a footerView is attached as Fourth View
FooterView Top Constraint
Top constraint used as footerViewTopConstraint
Output
Case 1 - Size is greater than scrollView Height
Case 2 - Expected Output
Attaching the view i am planning to design. I would like to position the Buttons with respect to Superview and their Width and Height must increase proportionally to the Screen Size rather than remaining fixed.
Attaching the screen preview:
This is an example just for one row of your buttons, so they can be reused for other UI elements.
Put these constraints onto your buttons:
LEFT BUTTON:
left leading constraint
top leading constraint
height constraint
RIGHT BUTTON
right trailing constraint
top leading constraint
height constraint
And constraints related to both buttons:
(you need to select both buttons to be able to apply relation constraints)
spacing constraint between buttons
equal width of these buttons
In Interface Builder it looks like this:
And these layout is universal, so I chose some device sizes to present:
iPhone 5
iPhone 6
iPhone 6 Plus
... etc.
For the Left Button:
Top constraint from the top of the view
Left constraint from the left edge of the view
Height constraint
Right constraint to the right button -> That will be 0
For the Right Button:
Top constraint from the top of the view
Right constraint from the right edge of the view
Height constraint
Left constraint to the right button -> That will be 0
You can try to use StackView feature, supported from Xcode7, take a look at this tutorial. StackView Sample
My answer is in a bit different way. I prefer not to use size class until and unless specially required. Now for your requirement i will disable size class and i will add the constraint like below.
I will add a clear color alpha 0 UIView to the superview just above those buttons named SpacerView
SpacerView -
1) Leading to superView - 0 - For Alignment of SpacerView
2) Trailing to superView - 0 - For Alignment of SpacerView
3) Top to superView - 0 - For Alignment of SpacerView
4) Proportional Height to SuperView - For Dynamic Sizing Height of SpacerView
Button 1 -
1) Leading to superview - 0 - For Alignment of Button 1
2) Trailing to Button 2 - 0 - For Alignment of Button 1 and Button 2
3) Proportional height to super view - 40:568 - For Dynamic Sizing Height of Button 1
4) Equal width to Button 2 - 0 - For Sizing of Width of Button 2 equal as Button 1
5) Equal Height to Button 2 - 0 - For Sizing of Height of Button 2 equal as Button 1
6) Top to SpacerView - 0 - For Alignment of Button 1
7) Center Y to Button 2 - 0 - For Alignment of Button 2 equal as Button 1
Button 2 -
1) Trailing to superView - For Alignment of Button 2
Here not even a single constraint is extra as per your requirement. If you have still problem i can send you a testing repository which i will make for your understanding.
Steps
1. Take two button side by side.
2. Give constraint for left button leading, top to superview.
3. Select height for left button.
3. Press control drag cursor from left button to right button and select horizontal spacing(select space between two button)
4. Give constraint to right side button top, trailing to superview.
5. Select height for right button.
6. Now press command ,select both buttons and see pin option below right side there select equal widths.
7.If some warning is showing means , no problem just click remove that warnings.
I've found the solution. Following are the constraints which i provided
LEFT BUTTON:
1.left leading constraint
2. top leading constraint
RIGHT BUTTON
1.right trailing constraint
2.top leading constraint
Common for both
1.Equal heights constraint
2.Equal Widths constraint
To proportionally increase the height depending on the superview i added aspect ratio constraint from both buttons to the superview with button height 0.6 of superview height.
really new to the interface builder. I have 5 buttons evenly spaced. Setup in the iPhone5 screen. I want the spacing between the buttons and the boundaries to remain the same but the buttons to grow in size with the screen (keeping the same aspect ratio).
How would I setup the constraints for this ? Do I need to put invisible spacers between the buttons or something to do this?
Do like this:
Put all buttons inside UIView
Set constraint to UIView as leading, top ,Trailing, height and width.
Set constraints to all the buttons inside UIView as top,leading,width and height.
Then select first button and UIView together, and make them equal widths and set the multiplier of this constraint as per your number of buttons need, at this point set priority of UIView's width constraint to 900 (this is important). Same with button's width constraint.
Now select all buttons and set them as equal width and set the multiplier of this constraint as per your button's width.
Delete width constraint of all the buttons except first one.
View heirarchy:
Final Output:
Solutions:
I have started implementing constraints from the button in the center i.e. Button4
1) Constraints on Holder View
HolderView.centerY = superview.centery
HolderView trailing/leading constraints to superview
2) Constraints on Button4
Button4.width = Button4.height
Button4.width = HolderView.superview.width * (1/7) - 10
(yes it is not a typo Button4.width is relative to screen width not its holder view's width)
Button4.trailing to Spacer, Button4.leading to Spacer
Button4 bottom/top constraints to superview
Make all other buttons equal to Button4 (button in the center)
3) If you need to have the same arrangement for any number of button you just have to play with width constraint of the button in the center
Sample Project :
Link to Sample Project
Note: This solutions will work on only odd number of buttons
I'm trying to make layout inside scrollview using this one tutorial link
And get the following result link
It will be appreciated for any advices or tutorial links. It needs only vertical scrolling
I am sure there must be other ways to do this but a quick fix is :
1.) Create a width constraint on ContentView in Storyborad.
2.) IBOutlet that widthContraint and set its value to the view frame width in viewDidLoad.
Suppose the name of the constraint outlet is contentViewWidthContraint.
contentViewWidthContraint.constant = self.view.bounds.size.width;
Another alternative to do so from Storyboard, is to fix the Contentview width to the view's width from the storyboard or to the Scrollview, if Scrollview already has a Equal width contraint with superview . Add the "Equal Width" contraint from Contentview to either self.view or to Scrollview (if scrollview, already has the width contraint)
Have you set up the "ContentView" width to match with the scroll view width? I had the same problem and I fixed with "Equal Widths".
"Equal Widths" will tell to your "ContentView" to use the same width of the "Scroll View", which should be fitting the screen if you have set up the constrain properly.
You can do this easily on the storyboard.
Drag and drop, with right click (important!!!), from "ContentView" to "ScrollView"
Release the click, you will be prompted with a menu, select "Equal Widths".
This should fix your problem using the scrollview with AutoLayout from Storyboard editor.
You can find a full tutorial how to use ScrollView with Autolayout and Storyboard here.
I hope this is useful for you :)
In the Storyboard set the width of the elements contained in your UIScrollView equal to the width of this UIScrollView (by selecting all elements and the UIScrollView holding in the panel on the left of your Storyboard and then setting the 'Equal Widths' constraint under 'Pin' on the bottom of your Storyboard). Just pinning the right sides of the elements to that of the UIScrollView won't work as it will adjust the size of its "display view" to the width of the largest element and if this is smaller than the width of the UIScrollView all elements will just appear aligned to its left side.
There is also another possibility that offers a very good result.
You can mark a checkbox:
O programmatically:
scrollView.alwaysBounceVertical = true
Try to set it's width to 0 & height equal to content size like this:
self.scrollView.contentSize = CGSizeMake(0, self.scrollView.contentSize.height);
This will work as you want. Try it & tell if still facing any issue.
For disabling the horizontal scroll, you can set the content size in the -(void)scrollViewDidScroll method.
[self.scrollView setContentOffset: CGPointMake(0, self.scrollView.contentOffset.y)];
self.scrollView.directionalLockEnabled = YES;
This is because scroll view have no idea where your content should end.
But when at least one item inside your scroll view has its "trailing space" constraint attached to a view outside the scroll view (usually a view the scroll view is sitting in or some other view of a higher level, which "knows" its width) - the scroll view will automatically get an idea about your wanted width and won't scroll horizontally (unless that trailing constraint implies having your content outside the screen).
Better if all items inside scroll view have their "trailing space" constraints connected either to each other or to a view outside the scroll view. But not the scroll view itself.
No additional code or extra constraints needed for this to work.
Too set UIScrollView constraints as like below code so it will occupied whole screen.Not exceed the screen size.
Leading Space = 0 from mainView
Top Space = 0 from mainView
Bottom Space = 0 from mainView
Trailing Space = 0 from mainView
You need to set the width of UIScrollView equal to or less than the width of your Parent View. Two ways to do it:
1) You can do this in Storyboard via layout constraints
2) You can do this programatically:
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.scrollView.contentSize.height);
i'm trying to develop a calculator using swift (see image)
since i have not entered any constraints, when i run the app on iphone screen larger than 4 inches, buttons remain in the same position (see image)
which constraints can i enter to ensure that the size of the buttons can grow with the increase of the screen size? Note that the red view is a content view inside a scroll view so with the following hierarchy:
View Controller
Scroll View
Content Red View
Buttons
where scroll view has the following constraints: (leading, trailing, bottom and top to his superview) while the content view has: (leading, trailing, bottom, top, equal width and equal height to scroll view)
EDIT: in response to Rizwan Shaikh
it works, the only problem is that the container view (red) has become lower than the scroll view (green) when i run the app with iphone 6/6 plus (see image), rather on the iPad the buttons exceeds the size of the container view forcing the scroll view to scroll vertically, why this happening?
EDIT 2: in response to Rizwan Shaikh
Thank you!
you should used constraint like
firstButton LeadingSpace = 20 from mainView
secondButton LeadingSpace = 20 from firstButton
thirdButton LeadingSpace = 20 from secondButton
thirdButton TrailingSpace = 20 from mainView
also select all the button in the given row go to Editor -> Pin -> widths equality
it will make your all button of same widths
similarly specify the top and bottomSpace like this
firstButton TopSpace = 20 from mainView
fourthButton topSpace = 20 from firstButton // consider 3 button in one row
fourthButton BottomSpace = 20 from MainView