How to add Scroll View in Swift 5? - ios

I wanna add scroll view in my project but in swift 5 I can't add it I tried many ways
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var imageViewBottomConstraint: NSLayoutConstraint!
#IBOutlet weak var imageViewLeadingConstraint: NSLayoutConstraint!
#IBOutlet weak var imageViewTopConstraint: NSLayoutConstraint!
#IBOutlet weak var imageViewTrailingConstraint: NSLayoutConstraint!

1.Add scrollView(1) in storyboard, add needed constraint to top/bottom/trailing/leading.
2.Then uncheck "Content Layout Guides" in Size inspector section for your scrollView.
3.Then you need to put into your scrollView new UIView(2), its constraints are for top/bottom/trailing/leading to superView(1) and equal width to superView(1).
4.Then the height of your view(2) you can add as constraint or you can add the content, which will give the height to your view(2).
Example with the height setted
Example with the content, which give the height to your view(2)

It works 100% when I Disabling the content layout guides in properties

If you use interface builder first of all add your scroll view and set scroll view constraint (top, bottom, leading and trailing) as (0,0,0,0). View hierarchy must be like this view -> scroll view -> view(content view). Again add constraints for your content view. Content view must have equal width and equal height with parent view (Scroll View). Control drag from content view to scroll view in Document Outline
For more information you can look at this https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithScrollViews.html

You don't need to uncheck Content Layout Guides(it's there to help us). It's actually not that hard to set it up. Here's how to do it using Xcode 11+ and supporting iOS 11+
1 - Add ScrollView and set top, bottom, leading and trailing constraints to 0 in relation to its superview
2 - Add a Content View(any UIView), drag a connection to the Content Layout Guide and set leading,top,trailing and bottom constraints to 0(make sure to set it to 0)
3 - Drag from your Content View to the Frame Layout Guide and set it to Equal Width
4 - Add a height constraint constant to the Content View

You can skip constraints altogether.
Add the ScrollView to your storyboard.
Create an IBOutlet in your ViewController.
Set the scrollview's height: scrollView.contentSize = (CGSize(width: desiredWidth, height: desiredHeight)
The desired width can be either a number or the width of another view. You can take the main view's width for exemple, by creating an IBOutlet to it: scrollView.contentSize = (CGSize(width: mainView.frame.size.width, height: desiredHeight)
The desired height is whatever value you require for the content to be shown in full while scrolling.
I find this way much easier to understand and control.

Related

How to set scrollview height programmatically

How can I set the scrollview height programmatically in Xcode 9 with Swift 4? I've set a constraint for the scrollview height and added that as an outlet. But when I change the outlet constant value programmatically it doesn't change the height.
Example:
#IBOutlet weak var scrollview_height: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
self.scrollview_height.constant = 245
}
The height of the ScrollView should be given by it's content and not for you to change manually. At best if you want to do something like that, you have a view inside the scrollView and change the size of that view instead.
Step-by-step:
Add a ScrollView to your view. Set it's constraints (no height or width)
Add a View inside the ScrollView and set it's constraints. Additionally for a vertical scroll you might want to set it's width equal to the SuperView and ensure it has a height.
Create an IBOutlet for the height of the view
update the constant value of the constraint in code
If it does not update as expected, run a layoutIfNeeded on your superview after updates
You have to increase the content Size of your scrollView instead of increasing the frame of scrollView.
self.scrollview.contentSize = CGSize(width: screenWidth, height: yourDesiredHeight)
the scrollable contentSize of scrollView will change According to it.

View at the bottom in a UIScrollView, with AutoLayout

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

UIStackView not updating after updating height of subview (UITableView with no scroll) while inside a ScrollView

How to make a UIStackView re-distribute it's sub-UITableViews while the stackView is inside a scrollview?
My layout hierarchy is based on the official documentation from apple about Dynamic content for StackViews
- UISCrollView
- UIStackView
- UIView A
- UIView B
- UIView C
- UITableView X
- UITableView Y
- UIView D
The constraints are set as documented. The initial layout of the StackView is correct showing all visible subviews. When forcing the regular views to expand beyond the screen's height, scrolling is working as expected. Also when viewing the layout in the storyboard, everything stacks as expected.
At this point the UITableViews are empty. As soon as I add content to the tableView the problem appears.
The problem
When I dynamically update the TableView's by calling .reloadData() on both of them I see their content appearing. (thanks to this answer about non-scrolling tableViews) but the UIStackView is not stacking the UITableViews.
UIView D is stacked below UIView C
UITableView X and UITableView Y also stacked below UIView B
My guess is that I need to invalidate the stackview, or somehow get it to redistribute it's subviews. How can I do this?
First, a warning:
What you're trying to achieve is not really standard iOS behavior. You should first consider a different approach like creating a single grouped table view with multiple sections. You can implement custom views inside your table view as section headers or footers.
Now if you really wanna go with your original approach...
... for some important reason you should be aware that a table view doesn't have an intrinsic content size by default. Thus, you need to tell the table view how tall it should be because otherwise it will only shrink down to a zero height.
You can achieve this by either subclassing UITableView and overriding its intrinsicContentSize() as Rob suggests in this answer to a similar question.
Or you add a height constraint to each of your table views and set their constants dynamically in code. A quick example:
Add both your table views to a vertical stack view in Interface Builder.
Give both table views a leading and a trailing constraint to pin their left and right edges to the stack view.
Create outlets for your table views in the respective view controller:
#IBOutlet weak var tableView1: UITableView!
#IBOutlet weak var tableView2: UITableView!
#IBOutlet weak var tableView1HeightConstraint: NSLayoutConstraint!
#IBOutlet weak var tableView2HeightConstraint: NSLayoutConstraint!
Override the updateViewConstraints() method of that view controller:
override func updateViewConstraints() {
super.updateViewConstraints()
tableView1HeightConstraint.constant = tableView1.contentSize.height
tableView2HeightConstraint.constant = tableView2.contentSize.height
}
Now whenever the content of any of your table views changes (e.g. when you add or remove rows or change the cell contents) you need to tell your view controller that it needs to update its constraints. Let's say you have a button that adds a cell to tableView1 each time you tap it. You might implement its action like this:
#IBAction func buttonTappen(sender: AnyObject) {
// custom method you implement somewhere else in your view controller
addRowToTableView1DataSource()
// reload table view with the updated data source
tableView1.reloadData()
// triggers an updateViewConstraints() call
view.setNeedsUpdateConstraints()
}
tl;dr:
A UITableView isn't intended for use without scrolling enabled and thus you always need to explicitly set its height when its contents change - may it be using constraints or by overriding the table view's intrinsic content size.

UITableView dynamic content size height inside UIScrollView with AutoLayout

I have a UIScrollView, inside this UIScrollView I have a UIView and inside the UIView I have some UITextField's, some UILabel's and at the bottom there is a UITableView.
I want the UITableView to fit it's content height, the UIView to fit it's content height and the UIScrollView to fit it's content height.
The UITableView height might change as I add / remove cells from it during usage.
What is the best way to handle it using AutoLayout?
- UIViewController
-- UIView
--- UIScrollView
---- UIView
----- UILabel
----- UITextField
----- UITextView
----- UITableView (at the bottom of the superview)
or as in the xib:
The best way to implement this is to scrap the hierarchy that you have now and do the following...
- UIViewController (or UITableViewController)
--- UITableView
----- UIView (as the tableView.tableHeaderView)
------- UILabel
------- UITextField
------- UITextView
----- Rest of the cells for the table view.
The tableView.tableHeaderView is a single (not reusable, concrete) view that is placed at the top of the content of the table view and scrolls with the content of the table view. It doesn't stick to the top of the screen like a section header view does.
This will allow you to delete the scroll view and place everything inside the table view and still doesn't change the methods that you are using to populate the cells as that remains untouched.
#Jan Greve is correct. But if you still want to do it
Set Bottom Space to Container constraint between the Table View and its super view to 0
Increase/decrease the height constraint of the Table View with each insert/delete (You will have to do this programmatically)
Set the content offset of the scrollview to the new view height
The best part of AutoLayout is now you don't have to worry about UIScrollView content size.
If you set all constraints properly(without any warnings) AutoLayout manage content size for scrollView itself.
Set all subview's constraints but don't add height and width constraints.
And for contentSize add bottom constraint of inner view (subview of scrollview) to UIScrollView. This will increaser scrollView content size and height as per inner view expand or shrink.
For more details: I asked question for same, you can check it. You can find code in question itself.
You can set a fixed height to the tableView and link the constraint to an outlet. Then you'd need to override viewDidLayoutSubviews() in order to set the height dynamically based on the contentSize of the table:
#IBOutlet weak var dynamicTVHeight: NSLayoutConstraint!
internal override func viewDidLayoutSubviews() {
let height = min(self.view.bounds.size.height, self.tableView.contentSize.height)
self.dynamicTVHeight.constant = height
self.view.layoutIfNeeded()
}

How to make two button center view on the center without cross border?

Have a look at the screenshot
I using stackview to stack the textfield, view, and tableview together. When I doing the constraint on the view,
I set the left constraint is 20, and right constraint as 20 on the both button, more over,
I add the width constraint on the both button but ended up the button show the width is different and cannot looks center on the simulator.
How do I make it to be center?
I'm working under the assumption you want your view to look like this:
V: textField - viewWithButtons - tableView
For your buttons, I'd highlight them and make them into a horizontal stack. Under attributes inspector, make the alignment fill, distribution fill equally, spacing 8 (or whatever you want).
From there, click your textFieldView, horizontalStackViewiewWithButtons, and tableView and then turn those into a vertical stack. From there, select your verticalStack from the document outline and click the Pin button at the lower-right corner of the screen. Left and right pins are 0, top pin is "Use Standard Value"
From there, work your way "inward" when you add constraints. The outer stack is mostly taken care of. You'll probably want to add a pin for the height of your textFieldView and your horizontalStackViewWithButtons.
I am also new to ios just my suggestion try this.
In storyboard set width constraint for both buttons
Create references for that constraints in your swift code.
#IBOutlet weak var height1: NSLayoutConstraint!
#IBOutlet weak var height2: NSLayoutConstraint!
In your viewwill appear method calculate width using your screen width for example
let screenSize: CGRect = UIScreen.mainScreen().bounds;
let width = screenSize.width;
//Then you need to remove the constraint spaces so
left(10) - Button1 - middle (10) - Button2 - Right(10)
So toatal 30
let width_available = screenSize.width - 30;
height2.constant = width_available/2
height1.constant = width_available/2
Edit 1:
The real simple solution just set equal width for both buttons from the storyboard.
Also you need horizontal spacing between the buttons

Resources