place UIView behind UILabel programmatically - swift

I want to ask. I want to make a UIView behind uilabel, I`m creating segmented Controll from collectionview right now. how can I make uiview behind uilabel?
this is my code
nameLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(nameLabel)
NSLayoutConstraint.activate([
nameLabel.topAnchor.constraint(equalTo: topAnchor),
nameLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
nameLabel.bottomAnchor.constraint(equalTo: bottomAnchor),
nameLabel.trailingAnchor.constraint(equalTo: trailingAnchor)
])
let backgroundView = UIView()
backgroundView.backgroundColor = .white
backgroundView.translatesAutoresizingMaskIntoConstraints = false
addSubview(backgroundView)
insertSubview(backgroundView, aboveSubview: nameLabel)
backgroundView.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor).isActive = true
backgroundView.bottomAnchor.constraint(equalTo: nameLabel.bottomAnchor).isActive = true
backgroundView.widthAnchor.constraint(equalTo: nameLabel.widthAnchor, multiplier: 1).isActive = true
backgroundView.heightAnchor.constraint(equalToConstant: 48).isActive = true

Views are added back to front. Just addSubview(backgroundView) before addSubview(newLabel).
Something like this should work:
let backgroundView = UIView()
backgroundView.backgroundColor = .white
backgroundView.translatesAutoresizingMaskIntoConstraints = false
addSubview(backgroundView)
nameLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(nameLabel)
NSLayoutConstraint.activate([
nameLabel.topAnchor.constraint(equalTo: topAnchor),
nameLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
nameLabel.bottomAnchor.constraint(equalTo: bottomAnchor),
nameLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
backgroundView.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor),
backgroundView.bottomAnchor.constraint(equalTo: nameLabel.bottomAnchor),
backgroundView.widthAnchor.constraint(equalTo: nameLabel.widthAnchor, multiplier: 1),
backgroundView.heightAnchor.constraint(equalToConstant: 48)
])

You can do with the #Vacawama answer, or you should notice that Apple provides 2 API like:
func sendSubviewToBack(_ view: UIView)
and
func bringSubviewToFront(_ view: UIView)
So you can deal with your view hierarchy programmatically.
Maybe you can try to move the backgroundView above the label in your storyboard, so you can have it behind (as it's first in, first out in the storyboard).
Or use sendSubviewToBack(backgroundView).
Or use bringSubviewToFront(nameLabel).
Or view.addSubview(backgroundView) then view.addSubview(nameLabel).

Related

How to programmatically pin a UIImageView

I read the documentation, but I just can't figure out what exactly is needed in my simple case.
The element is constantly jumping. I need just that.
I would be grateful for articles and so on. For a deeper understanding of this
class MyViewController : UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white
let imageView = UIImageView()
view.addSubview(imageView)
self.view = view
}
}
You are looking for auto layout constraints.
E.g. add to your code:
imageView.translatesAutoresizingMaskIntoConstraints = false
// add desired constraints here.
imageView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
...
You may want to set top, leading and trailing anchors, depending on the desired behavior.
imageView.translatesAutoresizingMaskIntoConstraints = false
// Apply constraint
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 10),
imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 1)
])

How to resize content view in UIScrollView programmatically?

Here is the issue: I need to add a view containing other subviews to a scroll view programmatically. In addition, I also need to make the frame of such a view to stick to the bounds of the main super view. The code below shows the approach I was trying to implement, but as you can see from the pictures below the 'contentView' is not updating its frame size when the screen is rotated. The initial code is taken from here for demonstration purposes. Any help would be greatly appreciated.
import UIKit
class TestViewController : UIViewController {
var contentViewSize = CGSize()
let contentView: UIView = {
let view = UIView()
view.backgroundColor = .magenta
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let labelOne: UILabel = {
let label = UILabel()
label.text = "Scroll Top"
label.backgroundColor = .red
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let labelTwo: UILabel = {
let label = UILabel()
label.text = "Scroll Bottom"
label.backgroundColor = .green
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let scrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .cyan
return v
}()
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
contentViewSize = view.bounds.size
labelTwo.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: (contentViewSize.width - labelTwo.frame.size.width - 16.0)).isActive = true
labelTwo.topAnchor.constraint(equalTo: contentView.topAnchor, constant: (contentViewSize.height - labelTwo.frame.size.height - 16.0)).isActive = true
}
override func viewDidLoad() {
super.viewDidLoad()
contentViewSize = view.bounds.size
view.backgroundColor = .yellow
self.view.addSubview(scrollView)
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8.0).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8.0).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true
scrollView.addSubview(contentView)
contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 16).isActive = true
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 16).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 16).isActive = true
contentView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 16).isActive = true
contentView.addSubview(labelOne)
labelOne.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16.0).isActive = true
labelOne.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16.0).isActive = true
contentView.addSubview(labelTwo)
labelTwo.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: (contentViewSize.width - labelTwo.frame.size.width - 16.0)).isActive = true
labelTwo.topAnchor.constraint(equalTo: contentView.topAnchor, constant: (contentViewSize.height - labelTwo.frame.size.height - 16.0)).isActive = true
labelTwo.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16.0).isActive = true
labelTwo.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -16.0).isActive = true
}
}
You made some odd changes to the code from the answer you linked to. Also, that answer is a little out-of-date.
Here's a better example. Assuming you want only vertical scrolling, this will:
add a Cyan scroll view, inset 8-pts on each side from the safe-area
add a Magenta "content view" to the scroll view, with 16-pts on each side constrained to the scroll view's contentLayoutGuide, with a width 32-pts less than the scroll view's frame (16-pts on each side)
add a label at top-left of the content view
add a label at bottom-right of the content view
constrain the bottom label 1500-pts below the top label (so it will scroll vertically)
Code:
class ScrollTestViewController : UIViewController {
let contentView: UIView = {
let view = UIView()
view.backgroundColor = .magenta
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let labelOne: UILabel = {
let label = UILabel()
label.text = "Scroll Top"
label.backgroundColor = .red
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let labelTwo: UILabel = {
let label = UILabel()
label.text = "Scroll Bottom"
label.backgroundColor = .green
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let scrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .cyan
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
// add the scroll view
self.view.addSubview(scrollView)
// add contentView to scroll view
scrollView.addSubview(contentView)
// add two labels to contentView
contentView.addSubview(labelOne)
contentView.addSubview(labelTwo)
// respect safe-area
let g = view.safeAreaLayoutGuide
// if you want to ignore the safe-area (bad idea),
// use this instead
//let g = view!
//scrollView.contentInsetAdjustmentBehavior = .never
// we're going to constrain the contentView to the scroll view's content layout guide
let scg = scrollView.contentLayoutGuide
NSLayoutConstraint.activate([
// constrain scrollView Top / Leading / Trailing / Bottom to view (safe-area)
// with 8-pts on each side
scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0),
scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -8.0),
// constrain contentView Top / Leading / Trailing / Bottom to scroll view's Content Layout Guide
// with 16-pts on each side
contentView.topAnchor.constraint(equalTo: scg.topAnchor, constant: 16.0),
contentView.leadingAnchor.constraint(equalTo: scg.leadingAnchor, constant: 16.0),
contentView.trailingAnchor.constraint(equalTo: scg.trailingAnchor, constant: -16.0),
contentView.bottomAnchor.constraint(equalTo: scg.bottomAnchor, constant: -16.0),
// if we only want vertical scrolling, constrain contentView Width
// to scrollView's Frame Layout Guide minus 32-pts (because we have 16-pts on each side)
contentView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor, constant: -32.0),
// constrain labelOne Top / Leading 16-pts to contentView Top / Leading
// (so it shows up at top-left corner)
labelOne.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16.0),
labelOne.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16.0),
// constrain labelTwo Bottom / Trailing 16-pts to contentView Bottom / Trailing
// (so it shows up at bottom-right corner)
labelTwo.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16.0),
labelTwo.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -16.0),
// constrain labelTwo Top to labelOne Bottom + 1500-pts
// so we'll have some vertical scrolling to get to it
labelTwo.topAnchor.constraint(equalTo: labelOne.bottomAnchor, constant: 1500.0),
])
}
}

Using UIScrollView with a minimum content top anchor causes visual glitch

I have a scroll view in which I have a content view. I set the scroll view's top anchor to be just above the bottom of an image. I set the content view's top anchor to actually be at the bottom of the image. That way you can pull down on the content and reveal up to the bottom of the image without being able to pull the content view down any further. However, this is causing the content to jump.
Here is my code:
class HomeParallaxScrollViewController: UIViewController {
private let topImageView = UIImageView(image: UIImage(named: "cat"))
private let contentView = UIView()
private let scrollView = UIScrollView()
private let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .gray
topImageView.contentMode = .scaleAspectFill
contentView.backgroundColor = .white
label.text = "SOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT"
label.textColor = .black
label.numberOfLines = 0
[contentView, label, topImageView, scrollView].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
scrollView.addSubview(contentView)
contentView.addSubview(label)
view.addSubview(topImageView)
view.addSubview(scrollView)
NSLayoutConstraint.activate([
topImageView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
topImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
topImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
topImageView.heightAnchor.constraint(equalToConstant: 200),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor),
scrollView.topAnchor.constraint(equalTo: topImageView.bottomAnchor, constant: -30),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
contentView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
contentView.topAnchor.constraint(lessThanOrEqualTo: topImageView.bottomAnchor), //This is what's causing the glitch
label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
label.topAnchor.constraint(equalTo: contentView.topAnchor),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
}
}
And here is that is happening:
Trying to add another top constraint -- particularly to an element outside the scroll view -- is a bad idea, and, as you see, won't work. I'm sure you noticed auto-layout conflict messages being generated.
One approach is to implement scrollViewDidScroll delegate func:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// limit drag-down in the scroll view to the overlap size
scrollView.contentOffset.y = max(scrollView.contentOffset.y, -30)
}
As the user drags-down to scroll, it will stop at 30-points.
Here is your example, with slight modifications -- I don't have your .plBackgroundLightGray or .PLSemiboldFont and I added an image load for the top image view -- but this should run as-is:
// conform to UIScrollViewDelegate
class HomeParallaxScrollViewController: UIViewController, UIScrollViewDelegate {
private let topImageView = UIImageView(image: UIImage(named: "cat"))
private let contentView = UIView()
private let scrollView = UIScrollView()
private let label = UILabel()
// this will be the "overlap" of the scroll view and top image view
private var scrollOverlap: CGFloat = 30.0
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// limit drag-down in the scroll view to scrollOverlap points
scrollView.contentOffset.y = max(scrollView.contentOffset.y, -scrollOverlap)
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .lightGray // .plBackgroundLightGray
topImageView.contentMode = .scaleAspectFill
if let img = UIImage(named: "background") {
topImageView.image = img
}
contentView.backgroundColor = .white
label.text = "SOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT"
label.font = UIFont.boldSystemFont(ofSize: 16) // .PLSemiboldFont(size: 16)
label.textColor = .black
label.numberOfLines = 0
[contentView, label, topImageView, scrollView].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
scrollView.addSubview(contentView)
contentView.addSubview(label)
view.addSubview(topImageView)
view.addSubview(scrollView)
NSLayoutConstraint.activate([
topImageView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
topImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
topImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
topImageView.heightAnchor.constraint(equalToConstant: 200),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor),
scrollView.topAnchor.constraint(equalTo: topImageView.bottomAnchor, constant: scrollOverlap),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
contentView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
// nope, not a good idea -- will cause constraint conflicts
//contentView.topAnchor.constraint(lessThanOrEqualTo: topImageView.bottomAnchor), //This is what's causing the glitch
label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
label.topAnchor.constraint(equalTo: contentView.topAnchor),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
// set delegate to self
scrollView.delegate = self
}
}

NSLayoutConstraint not resizing on rotation Swift

I just want to create a scrollview in the parent view, and pin to the view in code (and then go on to create a content view that is pinned and has the same width and height).
It should be simple, but when I rotate the device the scrollview does not rotate!
let scrollView = UIScrollView(frame: view.frame)
scrollView.backgroundColor = UIColor.blue
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
])
I also tried
scrollView.leadingAnchor.constraint(equalTo: scrollView.superview!.leftAnchor)
and various other combinations.
This is all called from within
viewDidLoad
If I start off in portrait and rotate to landscape (the image is on the view, the blue is the scrollview)
You should assign translatesAutoresizingMaskIntoConstraints property to false
let scrollView = UIScrollView(frame: view.frame)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.backgroundColor = UIColor.blue
view.addSubview(scrollView)

Swift - How put a stack of views into a scrollview

Currently I have a custom view (returns a UIStakView) that contains many views (UILabel, UIImageView, ...). It displays fine - on devices with plenty of height.
(BTW, this is all done programmatically.)
On small-screen devices it will only show the top part of the entire view. So my solution is to place it inside a UIScrollView. (This should be simple - but it's giving me lots of grief.)
But this won't display at all, what am I doing wrong / have missed?
Partial code below:
override init(frame: CGRect)
{
super.init(frame: frame)
imageFrame.addSubview(prodImage)
NSLayoutConstraint.activate([
prodImage.topAnchor.constraint(equalTo: imageFrame.topAnchor),
prodImage.trailingAnchor.constraint(equalTo: imageFrame.trailingAnchor),
prodImage.leadingAnchor.constraint(equalTo: imageFrame.leadingAnchor),
prodImage.bottomAnchor.constraint(equalTo: imageFrame.bottomAnchor),
])
imageView.addSubview(imageFrame)
NSLayoutConstraint.activate([
imageFrame.topAnchor.constraint(equalTo: imageView.topAnchor),
imageFrame.trailingAnchor.constraint(equalTo: imageView.trailingAnchor),
imageFrame.leadingAnchor.constraint(equalTo: imageView.leadingAnchor),
imageFrame.bottomAnchor.constraint(equalTo: imageView.bottomAnchor),
])
// More views...
let stack = UIStackView(arrangedSubviews: [imageView, prodName, prodPrice])
stack.axis = .vertical
stack.spacing = (self.frame.height > 400) ? (self.frame.height > 800) ? 15 : 10 : 5
stack.distribution = UIStackViewDistribution.fill
self.addSubview(stack)
NSLayoutConstraint.activate([
stack.leadingAnchor.constraint(equalTo: self.leadingAnchor),
stack.topAnchor.constraint(equalTo: self.topAnchor),
// stack.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -50),
stack.widthAnchor.constraint(equalTo: self.widthAnchor),
])
}
To make changes, I replaced the bottom stanza:
// self.addSubview(stack)
// NSLayoutConstraint.activate([
// stack.leadingAnchor.constraint(equalTo: self.leadingAnchor),
// stack.topAnchor.constraint(equalTo: self.topAnchor),
//// stack.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -50),
// stack.widthAnchor.constraint(equalTo: self.widthAnchor),
// ])
let scrollView = UIScrollView()
// scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(stack)
NSLayoutConstraint.activate([
stack.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
stack.topAnchor.constraint(equalTo: scrollView.topAnchor),
stack.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -50),
stack.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
])
self.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
scrollView.topAnchor.constraint(equalTo: self.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -50),
scrollView.widthAnchor.constraint(equalTo: self.widthAnchor),
])
As you can see, I tried disabling auto-constraints for the scroll view to make it fit the it's parent... All attempts failed.
How can I make this scroll view visible?
Possible mistake:
You are setting the stack view's leading / trailing to the scroll view.
If you print the frame's you might understand that the width is zero
This is because that:
stack view's width can't be determined based on the scroll view.
scroll view is a special view because it's content can be larger than the scroll view.
so you need to explicitly set the content view's (stack view's) width
Possible Fix 1:
Instead of setting it based on the scrollView set it on the view (assuming scrollView is added as a subview to viewController's view)
stack.leadingAnchor.constraint(equalTo: view.leadingAnchor),
stack.topAnchor.constraint(equalTo: view.topAnchor),
Possible Fix 2:
You set the stack view's width anchor explicitly
Example:
Given below is a simple example of how to use stack view with the scroll view.
Your broad idea is correct.
Scroll View has a stack view
The stack view has a few subviews
Screen Shot:
General Explanation:
Scroll view is special because a scroll view's content can be wider and taller than the scroll view itself (allowing it to scroll)
So the content's width and height should not be tied to the scroll view
The content's width and height should be set without the scroll view having any part to play
Strategy
As you have pointed out, I like to use a Scroll view and content view
Add the actual content to the stack view and let the stack view grow
So as long as the stack view's constraints to the scroll view are set properly things should fall in place.
Debugging:
Always print the frame values in viewDidAppear to see if things match your expectation
Example Code:
class ViewController: UIViewController {
let scrollView = UIScrollView()
let contentView = UIStackView()
let redView = UIView()
let greenView = UIView()
let yellowView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
setupScrollView()
setupContentView()
setupRedView()
setupGreenView()
setupYellowView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("scroll view = \(scrollView.frame)")
print("content view = \(contentView.frame)")
print("red view = \(redView.frame)")
print("green view = \(greenView.frame)")
print("yellow view = \(yellowView.frame)")
}
private func setupScrollView() {
scrollView.backgroundColor = .darkGray
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
private func setupContentView() {
contentView.axis = .vertical
contentView.distribution = .fill
contentView.alignment = .fill
scrollView.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
//Strategy is:
//content view's leading / trailing anchors are set to view controller's view
//content view's top / bottom anchors are set to scroll view
contentView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
contentView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
}
private func setupRedView() {
redView.backgroundColor = .red
redView.heightAnchor.constraint(equalToConstant: 400).isActive = true
contentView.addArrangedSubview(redView)
}
private func setupGreenView() {
greenView.backgroundColor = .green
greenView.heightAnchor.constraint(equalToConstant: 400).isActive = true
contentView.addArrangedSubview(greenView)
}
private func setupYellowView() {
yellowView.backgroundColor = .yellow
yellowView.heightAnchor.constraint(equalToConstant: 400).isActive = true
contentView.addArrangedSubview(yellowView)
}
}