To solve the challenge with UILayoutGuides only the following two methods must be changed to be like that:
func updateOffScreenLabel() {
let layoutGuide = UILayoutGuide()
view.addLayoutGuide(layoutGuide)
layoutGuide.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
layoutGuide.trailingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
nextQuestionLabel.centerXAnchor.constraint(equalTo: layoutGuide.centerXAnchor).isActive = true
}
func animateLabelTransitions() {
view.layoutIfNeeded() //Forces any outstanding layout changes to occur
nextQuestionLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
let layoutGuide = UILayoutGuide()
view.addLayoutGuide(layoutGuide)
layoutGuide.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
layoutGuide.leadingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
currentQuestionLabel.centerXAnchor.constraint(equalTo: layoutGuide.centerXAnchor).isActive = true
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 0.1, options: [.curveLinear], animations: {
self.currentQuestionLabel.alpha = 0
self.nextQuestionLabel.alpha = 1
self.view.layoutIfNeeded()
}) { _ in
swap(&self.currentQuestionLabel, &self.nextQuestionLabel)
swap(&self.currentQuestionLabelCenterXConstraint, &self.nextQuestionLabelCenterXConstraint)
self.updateOffScreenLabel()
}
}
Anyway the old way works fine too since iOS 10. Maybe the problem mentioned by the authors was in the previous SDKs. Even changing nextQuestionLabel.alpha = 1 in viewWillAppear() didn’t show the nextQuestionLabel on the screen. The value of the view.bounds.width property must change as soon as the screen changes including the rotation.
1 Like
im so lost i am trying to get to know the forum on how it works
You post here your questions and check for solutions.
I’d caution against this approach. Every time you declare and add an instance of UILayoutGuide you are adding another instance to the collection. Running this repeatedly would balloon memory usage.
Here is my approach:
@IBOutlet var answerLabel: UILabel!
var layoutGuide: UILayoutGuide! = UILayoutGuide()
override func viewDidLoad() {
super.viewDidLoad()
currentQuestionLabel.text = questions[currentQuestionIndex]
view.addLayoutGuide(layoutGuide)
nextQuestionLabelCenterXConstraint.isActive = false
layoutGuide.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
layoutGuide.trailingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
updateOffScreenLabel()
}
func updateOffScreenLabel() {
nextQuestionLabelCenterXConstraint = nextQuestionLabel.centerXAnchor.constraint(equalTo: layoutGuide.centerXAnchor)
nextQuestionLabelCenterXConstraint.isActive = true
}
func animateLabelTransitions() {
// Force any outstanding layout changes to occur
view.layoutIfNeeded()
// Animate the alpha and center the X constraints
let screenWidth = view.frame.width
currentQuestionLabelCenterXConstraint.constant += screenWidth
nextQuestionLabelCenterXConstraint.isActive = false
nextQuestionLabelCenterXConstraint = nextQuestionLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor)
nextQuestionLabelCenterXConstraint.isActive = true
view.isUserInteractionEnabled = false
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 1, options: [.curveLinear], animations: {
self.currentQuestionLabel.alpha = 0
self.nextQuestionLabel.alpha = 1
self.view.layoutIfNeeded()
}, completion: { _ in
self.currentQuestionLabelCenterXConstraint.isActive = false
swap(&self.currentQuestionLabel, &self.nextQuestionLabel)
swap(&self.currentQuestionLabelCenterXConstraint, &self.nextQuestionLabelCenterXConstraint)
self.updateOffScreenLabel()
self.view.isUserInteractionEnabled = true
})
}
Setting a constraint’s isActive flag to false allows you to update the value without a constraint conflict arising. Now we just create one instance of layout guide and reuse it.