Revert NSLayoutConstraint of UIView after changing the constraint - ios

Currently, I am expanding a custom view inside a scrollview to
fullscreen after the user taps on it. But I want the View to come back
to the original position once the user taps on it again. Note:- I have
set the original custom view position inside the scrollview on Xib
visually, I haven't added the code programmatically to add views in
scroll view.
Here is my code to expand:-
let frameAnimator = UIViewPropertyAnimator(duration: 0.6, dampingRatio: 1) {
self.playerDescriptionView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 0).isActive = true
self.playerDescriptionView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: 0).isActive = true
self.playerDescriptionView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0).isActive = true
self.playerDescriptionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true
self.view.layoutIfNeeded()
}
frameAnimator.startAnimation()
So, how can I set the constraint back to the original position while minimizing the view, because I have not set the view constraint programmatically?

Related

Programmatic constraints cut the bottom of my label off

I have a Nib file with a root UITableViewCell and child UILabel that I anchor at run time using programmatic constraints
lblAccountItemTitle.translatesAutoresizingMaskIntoConstraints = false
lblAccountItemTitle.topAnchor.constraint(lessThanOrEqualTo: self.topAnchor, constant: 16).isActive = true
lblAccountItemTitle.bottomAnchor.constraint(lessThanOrEqualTo: self.bottomAnchor, constant: -16).isActive = true
lblAccountItemTitle.leadingAnchor.constraint(equalTo: imgAccountItemLeft.trailingAnchor, constant: 16).isActive = true
lblAccountItemTitle.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -32).isActive = true
lblAccountItemTitle.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
Also, I've noticed that the shorter I make my bottom anchor, the less clipped the text is
How can I get rid of the clipping while still maintaining the equal 16 vertical padding?
change the both image and label bottom anchor from equalTo to lessThanOrEqualTo
lblAccountItemTitle.bottomAnchor.constraint(lessThanOrEqualTo: self.bottomAnchor, constant: -16).isActive = true
I was programmatically pinning the label to the cell and not to the Content View
self.topAnchor
should've been
self.contentView.topAnchor

Why width of view always return zero?

I'm setting up a view programmatically with all the constraints. Then I want to get its width (which vary from a device to another) but it always return zero when I print it.
here is my code:
let myView = UIView()
view.addSubview(myView)
myView.translatesAutoresizingMaskIntoConstraints = false
myView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 15).isActive = true
myView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -15).isActive = true
myView.topAnchor.constraint(equalTo: view.topAnchor, constant: 80).isActive = true
myView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -60).isActive = true
myView.backgroundColor = .blue
let myWidth1 = myView.frame.size.width
let myWidth2 = myView.bounds.width
print(myWidth1)
print(myWidth2)
however, the view actually has a width as shown in this screenshot:
For programmatic development, you should create that view in loadView(). viewDidLoad() is the lifecycle method that is called after the view has been loaded into memory; however, the view hasn't yet been rendered visually. You can get subview dimensions in viewDidLayoutSubviews(), which will be called throughout view mutations (like device orientation changes) or a method like viewDidAppear() that will only be called effectively once.

Issue with constraints inside a UITableViewCell

I have a custom cell for a UITableView. I'd like the following elements inside the cell:
1) UITextView with the following constraints:
it starts at the top left corner of the cell
it goes from the left side of the cell + 10 until the right side of the cell - 10.
its bottom should be 5 points above the next element (see 2 below)
2) UIButton with the following constraints:
it is X and Y centered in the cell
it goes from the left side of the cell + 20 until the right side of
the cell - 20.
it has a height of 60
The cell itself is defined with a height of 100.
However it seems my constraints have some conflicts according to the errors I get but I don't see where. Here is my code:
// constraints for the UIButton
answerTextButton.heightAnchor.constraint(equalToConstant: 60).isActive = true
answerTextButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20).isActive = true
answerTextButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20).isActive = true
answerTextButton.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
answerTextButton.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
// constraints for the UITextView
answerTextView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true
answerTextView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10).isActive = true
answerTextView.topAnchor.constraint(equalTo: topAnchor).isActive = true
answerTextView.bottomAnchor.constraint(equalTo: answerTextButton.topAnchor, constant: -5).isActive = true
What's the conflict here?
Thanks.
EDIT : I don't believe my mistake. While you are all right that the X-center constraint is useless, it was not the issue. The issue was... that I forgot to add "answerTextView.translatesAutoresizingMaskIntoConstraints = false".
Sorry for that, never happened before! So basically all my constraints for the UITextView were messy because of that. Adding it fixed everything but I kept your recommendation by removing the X-center constraint on the UIButton.
Copy and paste. It will work
// constraints for the UIButton
answerTextButton.heightAnchor.constraint(equalToConstant: 60).isActive = true
answerTextButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20).isActive = true
answerTextButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20).isActive = true
answerTextButton.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
// constraints for the UITextView
answerTextView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true
answerTextView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10).isActive = true
answerTextView.topAnchor.constraint(equalTo: topAnchor).isActive = true
answerTextView.bottomAnchor.constraint(equalTo: answerTextButton.topAnchor, constant: -5).isActive = true

AutoLayout not updating views programmatically - Swift

I have the following code where I'm creating and laying out everything in code. What I'm trying to do is modify the myTopContainer when a button is tapped but I can not make the width changed, only the height gets modified.
Any idea why?
func setupAutoLayout(){
NSLayoutConstraint.activate([
// My Container
myTopContainer.bottomAnchor.constraint(equalTo: myButton.topAnchor, constant: -5),
myTopContainer.heightAnchor.constraint(equalToConstant: 50),
myTopContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 15),
myTopContainer.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -15),
// My Button
myButton.widthAnchor.constraint(equalToConstant: 80),
myButton.heightAnchor.constraint(equalToConstant: 40),
myButton.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -15),
myButton.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -400)
])
}
#IBAction func relayoutViews(_ sender: Any) {
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn, animations: {
self.myTopContainer.heightAnchor.constraint(equalToConstant: 50).isActive = false
self.myTopContainer.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 15).isActive = false
// this is working, it changes the height
self.myTopContainer.heightAnchor.constraint(equalToConstant: 10).isActive = true
// this is not doing anything
self.myTopContainer.leadingAnchor.constraint(equalTo: self.myButton.trailingAnchor).isActive = true
self.view.layoutIfNeeded()
})
}
A line like this
self.myTopContainer.heightAnchor.constraint(equalToConstant: 50).isActive = false
Creates a new constraint every time. It doesn't modify the previously created constraint.
When you setupAutolayout you should save a reference to the constraints you want to later modify before actually calling NSLayoutConstraint.activate() on them.
Later you can set isActive to false on them.
For example:
var someConstraint: NSLayoutConstraint?
func setupAutoLayout(){
let aConstraint = myTopContainer.bottomAnchor.constraint(equalTo: myButton.topAnchor, constant: -5)
someConstraint = aConstraint
NSLayoutConstraint.activate([
// My Container
aConstraint
])
}
func editConstraint() {
self.someConstraint?.isActive = false
}
Anyway be careful on logs when you edit constraints, it's probable that you could break something while editing. If you see those logs of broken constraint than it means that something is still wrong (even if it visually looks good, it could crash or not work properly in some other situation)

Swift iOS -Push uiview down while typing inside textfield

I have a textfield that I set to a height of >= 50. Underneath the textfield I have uiview that is anchored to the bottom of the textfield. Once the textfield gets past the 50 point height I want it to push the uiview down so the text continues downward. What's happening right now is it hits the bottom of itself and instead of pushing the uiview down it scrolls the text up and the uiview doesn't move.
How can i get the textfield to stop scrolling up and instead push the uiview down once the textfield goes past the 50 point height? I can use a textfield with number of lines to 0 instead but I'd rather use a textfield.
// imageView is pinned to the top of the screen
textView.topAnchor.constraint(equalTo: iamgeView.bottomAnchor, constant: 32).isActive = true
textView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 8).isActive = true
textView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -8).isActive = true
textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 50).isActive = true
bottomLine.topAnchor.constraint(equalTo: textView.bottomAnchor, constant: 8).isActive = true
bottomLine.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 8).isActive = true
bottomLine.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -8).isActive = true
bottomLine.heightAnchor.constraint(equalToConstant: 0.5).isActive = true
I had to disable scrolling on the textField
textView.isScrollEnabled = false

Resources