i have some labels as a buttons which each one filters my table view content. In one of my labels I need to move table view a little bottom.because I have to show another view to user and table view must go below.
i have constraints all my views in view did load method first and i should constraint my tableView in label listener again.
here is my code for first constraint
override func setupViews() {
super.setupViews()
view.addSubview(header)
view.addSubview(serachOptionView)
view.addSubview(tableView)
header.addSubview(mytitle)
view.addSubview(serachBarView)
serachBarView.addSubview(serachInCityLabel)
serachBarView.addSubview(serachInCountryLabel)
serachBarView.addSubview(serachInTransitLabel)
serachBarView.addSubview(advanceSearch)
serachBarView.addSubview(columnLabelLeft)
serachBarView.addSubview(columnLabelRight)
//TO - DO header
header.translatesAutoresizingMaskIntoConstraints=false
header.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive=true
header.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive=true
header.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive=true
header.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.17).isActive=true
header.backgroundColor = UIColor.init(patternImage: UIImage(named: "test.png")!)
// MARK -- serachBarView
serachBarView.translatesAutoresizingMaskIntoConstraints=false
serachBarView.trailingAnchor.constraint(equalTo: header.trailingAnchor, constant: -3).isActive=true
serachBarView.leadingAnchor.constraint(equalTo: header.leadingAnchor, constant: 3).isActive=true
serachBarView.bottomAnchor.constraint(equalTo: header.bottomAnchor, constant: -1).isActive=true
serachBarView.heightAnchor.constraint(equalTo: header.heightAnchor, multiplier: 0.27).isActive=true
// MARK -- INCity
serachInCityLabel.translatesAutoresizingMaskIntoConstraints=false
serachInCityLabel.trailingAnchor.constraint(equalTo: serachBarView.trailingAnchor, constant: -5).isActive=true
serachInCityLabel.topAnchor.constraint(equalTo: serachBarView.topAnchor, constant: 1).isActive=true
serachInCityLabel.bottomAnchor.constraint(equalTo: serachBarView.bottomAnchor, constant: -1).isActive=true
serachInCityLabel.widthAnchor.constraint(equalTo: serachBarView.widthAnchor, multiplier: 0.23).isActive=true
// MARK -- columnLabelRight
columnLabelRight.translatesAutoresizingMaskIntoConstraints=false
columnLabelRight.trailingAnchor.constraint(equalTo: serachInCityLabel.leadingAnchor, constant: 0).isActive=true
columnLabelRight.topAnchor.constraint(equalTo: serachInCityLabel.topAnchor, constant: 4).isActive=true
columnLabelRight.bottomAnchor.constraint(equalTo: serachInCityLabel.bottomAnchor, constant: -4).isActive=true
columnLabelRight.widthAnchor.constraint(equalToConstant: 1.5).isActive=true
// MARK -- INCountry
serachInCountryLabel.translatesAutoresizingMaskIntoConstraints=false
serachInCountryLabel.trailingAnchor.constraint(equalTo: columnLabelRight.leadingAnchor, constant: 0).isActive=true
serachInCountryLabel.topAnchor.constraint(equalTo: serachBarView.topAnchor, constant: 1).isActive=true
serachInCountryLabel.bottomAnchor.constraint(equalTo: serachBarView.bottomAnchor, constant: -1).isActive=true
serachInCountryLabel.widthAnchor.constraint(equalTo: serachBarView.widthAnchor, multiplier: 0.24).isActive=true
// MARK -- columnLabelRight
columnLabelLeft.translatesAutoresizingMaskIntoConstraints=false
columnLabelLeft.trailingAnchor.constraint(equalTo: serachInCountryLabel.leadingAnchor, constant: 0).isActive=true
columnLabelLeft.topAnchor.constraint(equalTo: serachInCountryLabel.topAnchor, constant: 4).isActive=true
columnLabelLeft.bottomAnchor.constraint(equalTo: serachInCountryLabel.bottomAnchor, constant: -4).isActive=true
columnLabelLeft.widthAnchor.constraint(equalToConstant: 1.5).isActive=true
// MARK -- INTranis
serachInTransitLabel.translatesAutoresizingMaskIntoConstraints=false
serachInTransitLabel.trailingAnchor.constraint(equalTo: serachInCountryLabel.leadingAnchor, constant: 0).isActive=true
serachInTransitLabel.topAnchor.constraint(equalTo: serachBarView.topAnchor, constant: 1).isActive=true
serachInTransitLabel.bottomAnchor.constraint(equalTo: serachBarView.bottomAnchor, constant: -1).isActive=true
serachInTransitLabel.widthAnchor.constraint(equalTo: serachBarView.widthAnchor, multiplier: 0.24).isActive=true
// MARK -- advance search
advanceSearch.translatesAutoresizingMaskIntoConstraints=false
advanceSearch.trailingAnchor.constraint(equalTo: serachInTransitLabel.leadingAnchor, constant: 0).isActive=true
advanceSearch.topAnchor.constraint(equalTo: serachBarView.topAnchor, constant: 1).isActive=true
advanceSearch.bottomAnchor.constraint(equalTo: serachBarView.bottomAnchor, constant: -1).isActive=true
advanceSearch.widthAnchor.constraint(equalTo: serachBarView.widthAnchor, multiplier: 0.24).isActive=true
// MARK -- tableView
tableView.translatesAutoresizingMaskIntoConstraints=false
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive=true
tableView.topAnchor.constraint(equalTo: serachBarView.bottomAnchor, constant: 0).isActive=true
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive=true
tableView.delegate=self
tableView.dataSource=self
tableView.register(specialGoodCell.self, forCellReuseIdentifier: "myCell")
}
and move below my table View here :
@objc func labelAction(){
// MARK -- tableView
tableView.translatesAutoresizingMaskIntoConstraints=false
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive=true
tableView.topAnchor.constraint(equalTo: mypopUpView.bottomAnchor, constant: 0).isActive=true
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive=true
tableView.delegate=self
tableView.dataSource=self
tableView.register(specialGoodCell.self, forCellReuseIdentifier: "myCell")
}
and the result is no movment and this warnning :
nable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x28276f750 UIView:0x13fd45270.bottom == UIView:0x13fd4b2f0.bottom - 1 (active)>",
"<NSLayoutConstraint:0x28276f610 V:[UIView:0x13fd45270]-(0)-[UITableView:0x1400a0000] (active)>",
"<NSLayoutConstraint:0x28276f2a0 V:[UIView:0x13fd4b2f0]-(40)-[UIView:0x13fd18a40] (active)>",
"<NSLayoutConstraint:0x28276f8e0 UIView:0x13fd18a40.height == 0.16*UIView:0x13fe428e0.height (active)>",
"<NSLayoutConstraint:0x28276a990 V:[UIView:0x13fd18a40]-(0)-[UITableView:0x1400a0000] (active)>",
"<NSLayoutConstraint:0x28276cb40 'UIView-Encapsulated-Layout-Height' UIView:0x13fe428e0.height == 568 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x28276f2a0 V:[UIView:0x13fd4b2f0]-(40)-[UIView:0x13fd18a40] (active)>
System doesn't like multiple constraints assigned to an anchor with the same priority, because they conflict and the system 'breaks' one of them to satisfy at least one. Default priority for constraints, if not otherwise defined, is required
(1000). You can assign multiple constraints for an anchor and have the desired one active by assigning different priorities to them like defaultLow
and defaultHigh
and switch them on your behalf.
First thing is to keep a reference to your constraints in order to change them. Feeling free to update your code to the following:
class MyViewController: UIViewController {
// ...
// Keep a reference to the constraints you want to change
// depending on user interaction or desired state
// in your view controller class
var tableViewConstraintTopAnchor1: NSLayoutConstraint!
var tableViewConstraintTopAnchor2: NSLayoutConstraint!
// ...
}
Then in your setupViews function, assign them:
func setupViews() {
// ...
// adding subviews and other constraints
// ...
// MARK -- tableView
tableView.translatesAutoresizingMaskIntoConstraints=false
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive=true
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive=true
// assign (desired, but conflicting) constraints with different priority
tableViewConstraintTopAnchor1 = tableView.topAnchor.constraint(equalTo: serachBarView.bottomAnchor, constant: 0)
tableViewConstraintTopAnchor1.priority = .defaultHigh
tableViewConstraintTopAnchor1.isActive = true
tableViewConstraintTopAnchor2 = tableView.topAnchor.constraint(equalTo: mypopUpView.bottomAnchor, constant: 0)
tableViewConstraintTopAnchor2.priority = .defaultLow
tableViewConstraintTopAnchor2.isActive = true
tableView.delegate = self
tableView.dataSource = self
tableView.register(specialGoodCell.self, forCellReuseIdentifier: "myCell")
}
In your labelAction function, you simply switch the priority of the constraints and tell the system to update the layout of your view.
@objc func labelAction(){
// MARK -- tableView
// Switch the priority of the desired constraint to defaultHigh
// the other ones to defaultLow
tableViewConstraintTopAnchor1.priority = .defaultLow
tableViewConstraintTopAnchor2.priority = .defaultHigh
view.setNeedsLayout()
view.layoutIfNeeded()
}
It is also possible to put this in an UIView animation block and have the whole thing animated:
@objc func labelAction(){
// MARK -- tableView
UIView.animate(withDuration: 0.2) {
self.tableViewConstraintTopAnchor1.priority = .defaultLow
self.tableViewConstraintTopAnchor2.priority = .defaultHigh
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
}
}
Assigning both constraints for your tableView in viewDidLoad()
(or the function you call within it) only works, if mypopUpView
already exists and is in the same display hierarchy - didn't see it in your code so far ;)