iOS 9 Programmatic Constraints to a Nav Bar? - ios

I am trying to programmatically set my constraints to the top of my UIViewController's Nav Bar, but I can't see to get it to work properly. Here is my code:
func setup() {
let containerView = UIView()
containerView.backgroundColor = .red
containerView.translatesAutoresizingMaskIntoConstraints = false
let payeeNameTextField = UITextField()
payeeNameTextField.backgroundColor = .green
payeeNameTextField.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(containerView)
view.addSubview(payeeNameTextField)
//iOS 9 Constraints
//x,y,w,h
// Constraint To Nav Bar
containerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
containerView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
containerView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 20).isActive = true
// Constraint to Bottom Anchor
payeeNameTextField.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
payeeNameTextField.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
payeeNameTextField.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
payeeNameTextField.heightAnchor.constraint(equalToConstant: 50).isActive = true
}
I know setting it topAnchor is wrong, but I have tried to mess around with this and just cant seem to get the red background to show up.
Thanks in advance for any input!!

Related

Adding a vertical UIScrollView programmatically

I'm not making progress on this problem for a while now.
I'm trying to add a vertical scroll view to my app with a contentView (UIView). I added the contentView as a subview of the scrollView & added the scrollView as a subview of the main view. After that, I wasn't able to scroll and buttons + the searchbar weren't working anymore. It just felt like the app was frozen.
What I've done so far is the following:
Creating the scroll- and contentView directly in the class
let scrollView:UIScrollView = UIScrollView()
let contentView:UIView = UIView()
Setting up the scrollView
func setupScrollView() {
scrollView.translatesAutoresizingMaskIntoConstraints = false
contentView.translatesAutoresizingMaskIntoConstraints = false
scrollView.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
// Add scroll view to main view
self.view.addSubview(scrollView)
// Add content to scrollview
scrollView.addSubview(contentView)
// Constraints
scrollView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
scrollView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
contentView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
contentView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
contentView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
}
Adding several elements as subview to the contentView
// Add search bar to scroll content view
contentView.addSubview(searchBar)
The full code is available on my github repo
I looked through several similar problems and tutorials but somehow can't figure out what's wrong here.

UIScrollView not able to scroll?

I have this UIScrollView set up with a UIImageView and a UILabel.
However, it's not scrolling like I want it to. It's like it's not even there... How can I fix this? I just want it to be scrollable (even though theres nothing at the bottom to scroll to yet)
Thx in advance!
Here's my code:
// scrollView
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
// scrollView constraints
scrollView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
// Initialize profileImageView
profileImageView.image = #imageLiteral(resourceName: "neil")
profileImageView.translatesAutoresizingMaskIntoConstraints = false
profileImageView.layer.cornerRadius = 125 / 2
profileImageView.clipsToBounds = true
scrollView.addSubview(profileImageView)
// Add profileImageView constraints
profileImageView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 45).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 125).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 125).isActive = true
profileImageView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
// Add separator view
seperator.translatesAutoresizingMaskIntoConstraints = false
seperator.backgroundColor = UIColor.darkGray
scrollView.addSubview(seperator)
// seperator constraints
seperator.heightAnchor.constraint(equalToConstant: 2).isActive = true
seperator.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.8).isActive = true
seperator.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
seperator.topAnchor.constraint(equalTo: profileImageView.bottomAnchor, constant: 20).isActive = true
//nameLabel
let nameLabelFont = UIFont.monospacedDigitSystemFont(ofSize: 36, weight: UIFont.Weight.heavy)
nameLabel.font = nameLabelFont
nameLabel.text = currentUser.name
nameLabel.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(nameLabel)
// nameLabel constraints
nameLabel.topAnchor.constraint(equalTo: seperator.bottomAnchor, constant: 10).isActive = true
nameLabel.leadingAnchor.constraint(equalTo: seperator.leadingAnchor).isActive = true
You can't scroll because scrollView.contentSize isn't bigger then your view.
If you want make your screen scrollable you should set scrollView.contentSize.
Put scrollView.contentSize = CGSize(width: 1000, height: 1000) before view.addSubview(scrollView) to set your scrollable area to 1000x1000.
Generally scrollView.contentSize should be calculated base on UI elements inside UIScrollView e.g. size of 10 images with space between them.

Setting constant width on subview of UIStackView when axis is vertical

I have a UIScrollView that contains a UIStackView, and I add views to it and if the UIStackView needs more space than the screen has then it will scroll thanks to the UIScrollView.
I am able to set constant heights on the views, but I also need to set a specific width on them, so that they have a specific width and are also centered in the stack view.
Something like this, except the widthAnchor does not work.
import UIKit
class ViewController: UIViewController {
let scrollView: UIScrollView = {
let sv = UIScrollView()
sv.translatesAutoresizingMaskIntoConstraints = false
sv.backgroundColor = .gray
return sv
}()
let stackView: UIStackView = {
let sv = UIStackView()
sv.translatesAutoresizingMaskIntoConstraints = false
sv.axis = .vertical
return sv
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(scrollView)
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
scrollView.addSubview(stackView)
stackView.leftAnchor.constraint(equalTo: scrollView.leftAnchor).isActive = true
stackView.rightAnchor.constraint(equalTo: scrollView.rightAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
let view1 = UIView()
view1.backgroundColor = .red
let view2 = UIView()
view2.backgroundColor = .blue
let view3 = UIView()
view3.backgroundColor = .green
let view4 = UIView()
view4.backgroundColor = .purple
stackView.addArrangedSubview(view1)
stackView.addArrangedSubview(view2)
stackView.addArrangedSubview(view3)
stackView.addArrangedSubview(view4)
view1.heightAnchor.constraint(equalToConstant: 200).isActive = true
view2.heightAnchor.constraint(equalToConstant: 300).isActive = true
view3.heightAnchor.constraint(equalToConstant: 420).isActive = true
view4.heightAnchor.constraint(equalToConstant: 100).isActive = true
// This does not work.
// view1.widthAnchor.constraint(equalToConstant: 40).isActive = true
}
}
The alignment property on a UIStackView determines how its layout works perpendicular to its axis. By default, a UIStackView has an alignment of fill. In constraint terms, fill is like adding a constraint to (in this case) the left and right edges of the stack view for each arranged subview. These implicit constraints are likely causing your problem. Solution: set stackView.alignment = either leading, center, or trailing depending on your desired effect.

Programmatically layed out UIScrollView, and added auto layout to it's subviews, but it does not scroll

I am trying to figure out how UIScrollView works and I added some subviews to it with different backgroundColor properties. I layed out the subviews with ios9 autolayout but even if the views are outside of the screen, the UIScrollView still does not scroll.
import UIKit
class ViewController: UIViewController {
let scrollView: UIScrollView = {
let sv = UIScrollView()
sv.translatesAutoresizingMaskIntoConstraints = false
sv.backgroundColor = .gray
return sv
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(scrollView)
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
let view1 = UIView()
view1.backgroundColor = .red
let view2 = UIView()
view2.backgroundColor = .blue
let view3 = UIView()
view3.backgroundColor = .green
let view4 = UIView()
view4.backgroundColor = .purple
let views = [view1, view2, view3, view4]
for view in views {
scrollView.addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
}
view1.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
view1.leftAnchor.constraint(equalTo: scrollView.leftAnchor).isActive = true
view1.heightAnchor.constraint(equalToConstant: 140).isActive = true
view1.widthAnchor.constraint(equalToConstant: 140).isActive = true
view2.topAnchor.constraint(equalTo: view1.bottomAnchor, constant: 100).isActive = true
view2.leftAnchor.constraint(equalTo: view1.rightAnchor).isActive = true
view2.heightAnchor.constraint(equalToConstant: 140).isActive = true
view2.widthAnchor.constraint(equalToConstant: 140).isActive = true
view3.topAnchor.constraint(equalTo: view2.bottomAnchor, constant: 50).isActive = true
view3.leftAnchor.constraint(equalTo: view1.rightAnchor).isActive = true
view3.heightAnchor.constraint(equalToConstant: 140).isActive = true
view3.widthAnchor.constraint(equalToConstant: 140).isActive = true
view4.topAnchor.constraint(equalTo: view3.bottomAnchor, constant: 20).isActive = true
view4.leftAnchor.constraint(equalTo: view1.rightAnchor).isActive = true
view4.heightAnchor.constraint(equalToConstant: 140).isActive = true
view4.widthAnchor.constraint(equalToConstant: 140).isActive = true
}
}
When using Autolayout in UIScrollViews you have to pin subviews both to the top and bottom of the scrollview which allows the scrollview to calculate its contentSize.
Adding this line fixes it:
view4.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0).isActive = true

Swift: I'm not able to make autolayout constraints work for my UIScrollView

I'm trying to make a simple layout that should scroll vertically when views are too many to fit on the screen.
So this is what I have so far:
I created a scrollview and a container view like that
let mainScrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.isUserInteractionEnabled = true
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
let containerView: UIView = {
let view = UIView()
view.backgroundColor = .lightGray
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
Then I added the scrollview to the main view, added the container view to the scrollview and a couple of labels to the container view
view.addSubview(mainScrollView)
mainScrollView.addSubview(containerView)
containerView.addSubview(firstLabel)
containerView.addSubview(secondLabel)
I pinned the scrollview to the main view, and the container view to the scrollview. After that I started adding the labels inside the container view like this
mainScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
mainScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
mainScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
mainScrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
containerView.topAnchor.constraint(equalTo: mainScrollView.layoutMarginsGuide.topAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: mainScrollView.layoutMarginsGuide.bottomAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
firstLabel.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
firstLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 30).isActive = true
firstLabel.widthAnchor.constraint(equalToConstant: 50).isActive = true
firstLabel.heightAnchor.constraint(equalToConstant: 20).isActive = true
secondLabel.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
secondLabel.topAnchor.constraint(equalTo: firstLabel.bottomAnchor, constant: 750).isActive = true
secondLabel.widthAnchor.constraint(equalToConstant: 50).isActive = true
secondLabel.heightAnchor.constraint(equalToConstant: 20).isActive = true
The problem is that for some reason the scrollview is not able to calculate it's height and it doesn't scroll vertically. The second label remains invisible because it's too "low" on the screen.
I tried setting the bottom constraint of the container view to the bottom of the second label but I'm going nowhere honestly.
What am I missing? How can I set constraints to make the scrollview scroll with autolayout (without setting a specific height of the container view)?
Scrollview scrolls in either direction. So any view added to it would need some additional constraints to let the Scrollview calculate its content size.
You have pinned the container view to scroll view. If you are looking at a vertically scrolling view like a table view then you need to also set the width of the scroll to the container view so that it can calculate the width.
Next for height, its automatically calculated based on the UI elements added in the container view. Ensure that all of the labels have leading, trailing to the container and vertical spacing to each other and top of the container view. This will let the scroll view know the height needed.
self.scrollView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.translatesAutoresizingMaskIntoConstraints = false
self.label1.translatesAutoresizingMaskIntoConstraints = false
self.label2.translatesAutoresizingMaskIntoConstraints = false
self.label3.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(self.label1)
self.contentView.addSubview(self.label2)
self.contentView.addSubview(self.label3)
self.scrollView.addSubview(self.contentView)
self.view.addSubview(self.scrollView)
NSLayoutConstraint.activate([
self.scrollView.topAnchor.constraint(equalTo: self.view.topAnchor),
self.scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
self.scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor)
])
NSLayoutConstraint.activate([
self.contentView.topAnchor.constraint(equalTo: self.scrollView.topAnchor),
self.contentView.trailingAnchor.constraint(equalTo: self.scrollView.trailingAnchor),
self.contentView.bottomAnchor.constraint(equalTo: self.scrollView.bottomAnchor),
self.contentView.leadingAnchor.constraint(equalTo: self.scrollView.leadingAnchor),
self.contentView.widthAnchor.constraint(equalTo: self.scrollView.widthAnchor)
])
NSLayoutConstraint.activate([
self.label1.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
self.label2.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
self.label3.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
self.label1.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor),
self.label2.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor),
self.label3.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor)
])
NSLayoutConstraint.activate([
self.label1.topAnchor.constraint(equalTo: self.contentView.topAnchor),
self.label2.topAnchor.constraint(equalTo: self.label1.bottomAnchor),
self.label3.topAnchor.constraint(equalTo: self.label2.bottomAnchor),
self.label3.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor)
])
And when run, it won't complain about any constraint issues either. Same can be done for horizontal scroll.
Thank you very much #GoodSp33d, you pointed me to the right direction.
I added the width constraint as you said like that:
containerView.widthAnchor.constraint(equalTo: mainScrollView.widthAnchor).isActive = true
And the key point was to update the bottom constraint after all:
containerView.bottomAnchor.constraint(equalTo: secondLabel.bottomAnchor).isActive = true
Here is the full working code:
mainScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
mainScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
mainScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
mainScrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
containerView.topAnchor.constraint(equalTo: mainScrollView.topAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: mainScrollView.trailingAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: mainScrollView.bottomAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo: mainScrollView.leadingAnchor).isActive = true
containerView.widthAnchor.constraint(equalTo: mainScrollView.widthAnchor).isActive = true
firstLabel.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
firstLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 30).isActive = true
firstLabel.widthAnchor.constraint(equalToConstant: 50).isActive = true
firstLabel.heightAnchor.constraint(equalToConstant: 20).isActive = true
secondLabel.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
secondLabel.topAnchor.constraint(equalTo: firstLabel.bottomAnchor, constant: 550).isActive = true
secondLabel.widthAnchor.constraint(equalToConstant: 50).isActive = true
secondLabel.heightAnchor.constraint(equalToConstant: 20).isActive = true
containerView.bottomAnchor.constraint(equalTo: secondLabel.bottomAnchor).isActive = true
Thanks for the help.

Resources