I have the following code
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.showsHorizontalScrollIndicator = false
scrollView.showsVerticalScrollIndicator = false
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
let contentView = UIView()
contentView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(contentView)
contentView.backgroundColor = UIColor(red: 0.97, green: 0.98, blue: 0.99, alpha: 1.00)
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor)
])
// Large Label
let largeLabel: UILabel = {
let label = UILabel()
label.text = "Congrats!"
label.font = UIFont(name: "Inter-Bold", size: 24)
label.textAlignment = .center
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
// Small Label
let smallLabel: UILabel = {
let label = UILabel()
label.text = "Your finished the \(category.name) lesson."
label.font = UIFont(name: "Inter-Regular", size: 16)
label.textColor = .black
label.textAlignment = .center
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
// Image View
let animatedImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "fire"))
imageView.tintColor = .systemYellow
imageView.contentMode = .scaleAspectFit
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
contentView.addSubview(largeLabel)
contentView.addSubview(smallLabel)
contentView.addSubview(animatedImageView)
let totalScore = score + WUser.sharedInstance.getUserScore()
var nextLevel = ""
var currentLevel = ""
var toXP = 0
let pointsView = UIView()
pointsView.layer.cornerRadius = 20
pointsView.backgroundColor = .white
pointsView.layer.borderColor = UIColor.gray.cgColor
pointsView.layer.borderWidth = 1
pointsView.layer.masksToBounds = true
pointsView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(pointsView)
let pointsLabel: UILabel = {
let label = UILabel()
label.text = "Points Earned"
label.font = UIFont(name: "Inter-Bold", size: 16)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let percentageLabel: UILabel = {
let label = UILabel()
label.text = "+\(score + 5)"
label.font = UIFont(name: "Inter-Bold", size: 16)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let iconImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.image = UIImage(systemName: "star.fill")
imageView.tintColor = UIColor(red: 0.63, green: 0.14, blue: 0.92, alpha: 1.00)
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let progressView = UIProgressView(progressViewStyle: .default)
progressView.progress = 0
progressView.layer.cornerRadius = 10
progressView.layer.masksToBounds = true
progressView.trackTintColor = UIColor(red: 0.91, green: 0.91, blue: 0.91, alpha: 1.00)
progressView.progressTintColor = UIColor(red: 0.63, green: 0.14, blue: 0.92, alpha: 1.00)
progressView.translatesAutoresizingMaskIntoConstraints = false
if totalScore < 5 {
currentLevel = "Level 1"
nextLevel = "Starter"
toXP = 5 - totalScore
} else if totalScore < 50 {
currentLevel = "Starter"
nextLevel = "Trailblazer"
toXP = 50 - totalScore
} else if totalScore < 100 {
currentLevel = "Trailblazer"
nextLevel = "Champ"
toXP = 100 - totalScore
} else if totalScore < 200 {
currentLevel = "Champ"
nextLevel = "Genius"
toXP = 200 - totalScore
} else if totalScore < 500 {
currentLevel = "Champ"
nextLevel = "Genius"
toXP = 500 - totalScore
} else {
currentLevel = "Genius"
nextLevel = "Genius"
}
let xpLabel: UILabel = {
let label = UILabel()
label.text = "\(toXP) XP to \(nextLevel)"
label.font = UIFont(name: "Inter-Regular", size: 14)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
pointsView.addSubview(pointsLabel)
pointsView.addSubview(percentageLabel)
pointsView.addSubview(iconImageView)
contentView.addSubview(progressView)
contentView.addSubview(xpLabel)
NSLayoutConstraint.activate([
largeLabel.topAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.topAnchor, constant: 20),
largeLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
largeLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20),
// Small Label Constraints
smallLabel.topAnchor.constraint(equalTo: largeLabel.bottomAnchor, constant: 20),
smallLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
smallLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20),
animatedImageView.topAnchor.constraint(equalTo: smallLabel.bottomAnchor, constant: 40),
animatedImageView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
animatedImageView.widthAnchor.constraint(equalToConstant: 150),
animatedImageView.heightAnchor.constraint(equalToConstant: 150),
pointsView.topAnchor.constraint(equalTo: animatedImageView.bottomAnchor, constant: 50),
pointsView.widthAnchor.constraint(equalToConstant: 300),
pointsView.heightAnchor.constraint(equalToConstant: 50),
pointsView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
pointsLabel.leadingAnchor.constraint(equalTo: pointsView.leadingAnchor, constant: 16),
pointsLabel.centerYAnchor.constraint(equalTo: pointsView.centerYAnchor),
percentageLabel.trailingAnchor.constraint(equalTo: iconImageView.leadingAnchor, constant: -8),
percentageLabel.centerYAnchor.constraint(equalTo: pointsView.centerYAnchor),
iconImageView.trailingAnchor.constraint(equalTo: pointsView.trailingAnchor, constant: -16),
iconImageView.centerYAnchor.constraint(equalTo: pointsView.centerYAnchor),
iconImageView.widthAnchor.constraint(equalToConstant: 24),
iconImageView.heightAnchor.constraint(equalToConstant: 24),
progressView.leadingAnchor.constraint(equalTo: pointsView.leadingAnchor, constant: 16),
progressView.trailingAnchor.constraint(equalTo: pointsView.trailingAnchor, constant: -16),
progressView.topAnchor.constraint(equalTo: pointsView.bottomAnchor, constant: 30),
progressView.heightAnchor.constraint(equalToConstant: 20),
xpLabel.leadingAnchor.constraint(equalTo: progressView.leadingAnchor),
xpLabel.topAnchor.constraint(equalTo: progressView.bottomAnchor, constant: 10)
])
let instructionLabel = UILabel()
instructionLabel.text = "How would you rate the lesson?"
instructionLabel.textAlignment = .center
instructionLabel.font = UIFont(name: "Inter-Bold", size: 18)
instructionLabel.translatesAutoresizingMaskIntoConstraints = false
let starsStackView = UIStackView()
starsStackView.axis = .horizontal
starsStackView.alignment = .center
starsStackView.distribution = .equalSpacing
starsStackView.spacing = 10
starsStackView.translatesAutoresizingMaskIntoConstraints = false
for i in 1...5 {
let button = UIButton(type: .system)
button.tag = i
button.setTitle("★", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 30)
button.setTitleColor(.lightGray, for: .normal)
button.addTarget(self, action: #selector(starTapped(_:)), for: .touchUpInside)
starsStackView.addArrangedSubview(button)
}
let submitButton = UIButton(type: .system)
submitButton.setTitle("Submit Rating", for: .normal)
submitButton.backgroundColor = UIColor(red: 0.35, green: 0.25, blue: 0.55, alpha: 1.00)
submitButton.setTitleColor(.white, for: .normal)
submitButton.layer.cornerRadius = 20
submitButton.titleLabel?.font = UIFont(name: "Inter-Bold", size: 16)
submitButton.addTarget(self, action: #selector(submitRating), for: .touchUpInside)
submitButton.translatesAutoresizingMaskIntoConstraints = false
let closeButton = UIButton(type: .system)
closeButton.setTitle("Close", for: .normal)
closeButton.setTitleColor(.gray, for: .normal)
closeButton.titleLabel?.font = UIFont(name: "Inter-Bold", size: 16)
closeButton.addTarget(self, action: #selector(goBack), for: .touchUpInside)
closeButton.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(instructionLabel)
contentView.addSubview(starsStackView)
contentView.addSubview(submitButton)
contentView.addSubview(closeButton)
NSLayoutConstraint.activate([
instructionLabel.topAnchor.constraint(equalTo: xpLabel.bottomAnchor, constant: 30),
instructionLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
starsStackView.topAnchor.constraint(equalTo: instructionLabel.bottomAnchor, constant: 20),
starsStackView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
submitButton.topAnchor.constraint(equalTo: starsStackView.bottomAnchor, constant: 20),
submitButton.widthAnchor.constraint(equalToConstant: 250),
submitButton.heightAnchor.constraint(equalToConstant: 50),
submitButton.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
closeButton.topAnchor.constraint(equalTo: submitButton.bottomAnchor, constant: 20),
closeButton.widthAnchor.constraint(equalToConstant: 250),
closeButton.heightAnchor.constraint(equalToConstant: 50),
closeButton.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
closeButton.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20.0)
])
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
UIView.animate(withDuration: 1.5) {
progressView.setProgress(Float(Float(totalScore)/500), animated: true)
}
}
UIView.animate(withDuration: 1.0,
delay: 0,
options: [.autoreverse, .repeat],
animations: {
animatedImageView.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
}, completion: { _ in
animatedImageView.transform = .identity
})
Unfortunately, the elements are not centered on the page. They shift to the left of the screen.
See attached
Can someone please help?
I am pretty sure it appears like this because contentView's anchors aren't setup correctly. In your code, you have this constraint:
contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor)
This means that the right edge of contentView is pinned to the right edge of scrollView, but it does not guarantee that contentView will always match the width of scrollView.
If contentView's content expands beyond scrollView.width, scrollView will allow horizontal scrolling. If contentView's content is smaller than scrollView.width, contentView won't stretch automatically, and the content might not appear properly aligned to the right.
The correct way to setup constraints is
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor)
])