UPDATE AT THE BOTTOM
Inside my ViewController I have a TableView with CustomCells. The content being presented in those cells is depending on the userInput. I think the best way to explain the problem is to actually show it:
1. adding cells to the tableView:
looking as expected
2. Problem: after dismissing the ViewController and going back to it:
showing views that should actually be hidden in the first cell
By the way, when I open the View-Hirarchy in the Debugger, it is being displayed correctly !
Here is also another video for a better understanding: video
In this case I didn't add an image, but when going back to the viewController it still shows the imageContainerView(shadow) and also the content for the first cell.
Code:
My code is quite complex and messy so I you can follow me here:
setupViews in CustomCell:
I don't think that this is quite helpful, but I also don't think that the setup is the issue here.
func setupViews(){
contentView.addSubview(checkButton)
contentView.addSubview(mainStackView)
// main StackView
mainStackView.addArrangedSubview(label)
mainStackView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
mainStackView.leadingAnchor.constraint(equalTo: checkButton.trailingAnchor, constant: 15).isActive = true
mainStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -30).isActive = true
mainStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
//constrain wish label
labelHeightConatraint = label.heightAnchor.constraint(equalToConstant: 50)
labelHeightConatraint.priority = .defaultHigh
labelHeightConatraint.isActive = true
// constrain checkButton
checkButton.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 30).isActive = true
checkButton.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
checkButton.widthAnchor.constraint(equalToConstant: 40).isActive = true
checkButton.heightAnchor.constraint(equalToConstant: 40).isActive = true
mainStackView.addArrangedSubview(secondaryStackView)
secondaryStackViewHeightConstraint = secondaryStackView.heightAnchor.constraint(equalToConstant: 90)
secondaryStackViewHeightConstraint.priority = .defaultHigh
secondaryStackViewHeightConstraint.isActive = true
secondaryStackView.addArrangedSubview(imageContainerView)
imageContainerWidthConstraint = imageContainerView.widthAnchor.constraint(equalToConstant: 90)
imageContainerWidthConstraint.priority = .defaultHigh
imageContainerWidthConstraint.isActive = true
imageContainerView.addSubview(shadowLayer)
shadowLayer.widthAnchor.constraint(equalToConstant: 80).isActive = true
shadowLayer.heightAnchor.constraint(equalToConstant: 80).isActive = true
shadowLayer.topAnchor.constraint(equalTo: imageContainerView.topAnchor).isActive = true
shadowLayer.trailingAnchor.constraint(equalTo: imageContainerView.trailingAnchor, constant: -10).isActive = true
imageContainerView.addSubview(wishImage)
wishImage.widthAnchor.constraint(equalToConstant: 80).isActive = true
wishImage.heightAnchor.constraint(equalToConstant: 80).isActive = true
wishImage.topAnchor.constraint(equalTo: imageContainerView.topAnchor).isActive = true
wishImage.trailingAnchor.constraint(equalTo: imageContainerView.trailingAnchor, constant: -10).isActive = true
secondaryStackView.addArrangedSubview(thirdHelperView)
thirdHelperView.addSubview(thirdStackView)
thirdHelperViewHeightConstraint = thirdHelperView.heightAnchor.constraint(equalToConstant: 90)
thirdHelperViewHeightConstraint.priority = .defaultHigh
thirdHelperViewHeightConstraint.isActive = true
thirdStackView.addArrangedSubview(priceView)
priceView.heightAnchor.constraint(equalToConstant: 30).isActive = true
priceView.addSubview(priceImage)
priceView.addSubview(priceLabel)
thirdStackView.addArrangedSubview(linkView)
linkView.heightAnchor.constraint(equalToConstant: 30).isActive = true
linkView.addSubview(linkImage)
linkView.addSubview(linkTextView)
thirdStackView.addArrangedSubview(noteView)
noteView.heightAnchor.constraint(equalToConstant: 30).isActive = true
noteView.addSubview(noteImage)
noteView.addSubview(noteLabel)
priceImage.topAnchor.constraint(equalTo: priceView.topAnchor).isActive = true
priceImage.leadingAnchor.constraint(equalTo: thirdStackView.leadingAnchor).isActive = true
priceImage.heightAnchor.constraint(equalToConstant: 20).isActive = true
priceImage.widthAnchor.constraint(equalToConstant: 20).isActive = true
priceLabel.topAnchor.constraint(equalTo: priceView.topAnchor).isActive = true
priceLabel.leadingAnchor.constraint(equalTo: priceImage.trailingAnchor, constant: 10).isActive = true
priceLabel.trailingAnchor.constraint(equalTo: priceView.trailingAnchor, constant: -10).isActive = true
linkImage.topAnchor.constraint(equalTo: linkView.topAnchor).isActive = true
linkImage.leadingAnchor.constraint(equalTo: thirdStackView.leadingAnchor).isActive = true
linkImage.heightAnchor.constraint(equalToConstant: 20).isActive = true
linkImage.widthAnchor.constraint(equalToConstant: 20).isActive = true
linkTextView.topAnchor.constraint(equalTo: linkView.topAnchor).isActive = true
linkTextView.leadingAnchor.constraint(equalTo: linkImage.trailingAnchor, constant: 10).isActive = true
linkTextView.trailingAnchor.constraint(equalTo: linkView.trailingAnchor, constant: -10).isActive = true
noteImage.topAnchor.constraint(equalTo: noteView.topAnchor).isActive = true
noteImage.leadingAnchor.constraint(equalTo: thirdStackView.leadingAnchor).isActive = true
noteImage.heightAnchor.constraint(equalToConstant: 20).isActive = true
noteImage.widthAnchor.constraint(equalToConstant: 20).isActive = true
noteLabel.topAnchor.constraint(equalTo: noteView.topAnchor).isActive = true
noteLabel.leadingAnchor.constraint(equalTo: noteImage.trailingAnchor, constant: 10).isActive = true
noteLabel.trailingAnchor.constraint(equalTo: noteView.trailingAnchor, constant: -10).isActive = true
}
more importantly: cellForRowAt, where I actually hide/show the different views depending on the content. As you can see I actually call .isHidden on the ImageContainerView, priceView, linkView & noteView , if there content is empty ( which it is in the first cell )
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: WhishCell.reuseID, for: indexPath) as! WhishCell
cell.label.text = ""
cell.linkTextView.text = ""
cell.priceLabel.text = ""
cell.noteLabel.text = ""
cell.wishImage.image = UIImage()
let currentWish = self.wishData[indexPath.row]
cell.label.text = currentWish.name
cell.linkTextView.hyperLink(originalText: "Link öffnen", hyperLink: "Link öffnen", urlString: currentWish.link)
cell.priceLabel.text = currentWish.price
cell.noteLabel.text = currentWish.note
cell.wishImage.image = currentWish.image
cell.setupSuccessAnimation()
cell.noteView.isHidden = false
cell.priceView.isHidden = false
cell.linkView.isHidden = false
cell.imageContainerView.isHidden = false
cell.secondaryStackViewHeightConstraint.constant = 0
cell.thirdHelperViewHeightConstraint.constant = 0
if currentWish.image == nil || !currentWish.image!.hasContent {
cell.imageContainerView.isHidden = true
print("but its truue: \(cell.imageContainerView.isHidden)")
if currentWish.price != "" {
cell.thirdHelperViewHeightConstraint.constant += 30
cell.secondaryStackViewHeightConstraint.constant += 30
}
if currentWish.link != "" {
cell.thirdHelperViewHeightConstraint.constant += 30
cell.secondaryStackViewHeightConstraint.constant += 30
}
if currentWish.note != "" {
cell.thirdHelperViewHeightConstraint.constant += 30
cell.secondaryStackViewHeightConstraint.constant += 30
}
} else {
cell.secondaryStackViewHeightConstraint.constant = 90
cell.thirdHelperViewHeightConstraint.constant = 90
}
if currentWish.price == "" {
cell.priceView.isHidden = true
}
if currentWish.link == "" {
cell.linkView.isHidden = true
}
if currentWish.note == "" {
cell.noteView.isHidden = true
}
return cell
}
I have no idea why this happens. I don't think something is wrong with the setup as it works if I actually add the cells. It is simply not hiding the views when it actually should. The cellheight is also working as expected. Just the damn hiding...
I know this is a lot but I hope my problem is clear. If you need any thing more just let me know!
Update:
I added two print-statements inside cellForRowAt and is actually printing this:
print("but its truue: \(cell.imageContainerView.isHidden)")
print("but its truue: \(cell.shadowLayer.isHidden)")
but its truue: true
but its truue: false
so it is hiding the imageConatinerView correctly but not shadowLayer even though shadowLayer is a subView of imageContainerView??! Im stuck here...
You can use UIView debugging method to debug your UI.
There are four useful methods to debug:
hasAmbiguousLayout:
exerciseAmbiguityInLayout:
exerciseAmbiguityInLayout:
_autolayoutTrace:
And then you can use Xcode UI Debug to review your UI
Related
I have a vertical UIScrollView, allScrollView, and a horizontal UIScrollView, hourlyScrollView, nested inside the vertical UIScrollView. In each of the scroll views I have 10 other UIViews that will show data. Each of the views are assigned a UITapGestureRecognizer. I'm able to tap the views that are only in the vertical scroll, but none of the views in the nested horizontal scroll do anything when tapped. If anyone can help me it would be greatly appreciated as I've tried a lot of suggestions on here with no luck.
my view hierarchy:
-allScrollView (vertical)
-allContentView
-hourlyScrollView (horizontal)
-hourlyContentView
-10 UIViews
-dailyContentView
-10 UIViews
viewDidLoad()
let dailyContentView = UIView()
let hourlyContentView = UIView()
let hourlyScrollView = UIScrollView()
let allContentView = UIView()
let allScrollView = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
hourlyScrollView.translatesAutoresizingMaskIntoConstraints = false
hourlyContentView.translatesAutoresizingMaskIntoConstraints = false
allContentView.translatesAutoresizingMaskIntoConstraints = false
allScrollView.translatesAutoresizingMaskIntoConstraints = false
dailyContentView.translatesAutoresizingMaskIntoConstraints = false
layoutHourlyViews()
layoutDailyViews()
finishLayout()
}
create horizontal scroll content
func layoutHourlyViews() {
for subview in hourlyScrollView.subviews {
subview.removeFromSuperview()
}
for subView in hourlyContentView.subviews {
subView.removeFromSuperview()
}
var previousHour : UIView? = nil
for count in 1...10 {
let hourlyUIView = UIView()
hourlyUIView.backgroundColor = .blue
hourlyUIView.isUserInteractionEnabled = true
hourlyUIView.tag = count
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hourlyTap(_:)))
hourlyUIView.addGestureRecognizer(tapGesture)
let descriptionLabel = UILabel()
let borderView = UIView()
let borderViewTop = UIView()
let borderViewBottom = UIView()
borderViewTop.backgroundColor = .black
borderViewBottom.backgroundColor = .black
borderViewTop.translatesAutoresizingMaskIntoConstraints = false
borderViewBottom.translatesAutoresizingMaskIntoConstraints = false
borderView.translatesAutoresizingMaskIntoConstraints = false
hourlyUIView.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.text = "test"
borderView.backgroundColor = .black
hourlyUIView.addSubview(borderViewBottom)
hourlyUIView.addSubview(borderViewTop)
hourlyUIView.addSubview(descriptionLabel)
hourlyUIView.addSubview(borderView)
borderViewBottom.leadingAnchor.constraint(equalTo: hourlyUIView.leadingAnchor).isActive = true
borderViewBottom.trailingAnchor.constraint(equalTo: hourlyUIView.trailingAnchor).isActive = true
borderViewBottom.bottomAnchor.constraint(equalTo: hourlyUIView.bottomAnchor).isActive = true
borderViewBottom.heightAnchor.constraint(equalToConstant: 2).isActive = true
borderViewTop.leadingAnchor.constraint(equalTo: hourlyUIView.leadingAnchor).isActive = true
borderViewTop.trailingAnchor.constraint(equalTo: hourlyUIView.trailingAnchor).isActive = true
borderViewTop.topAnchor.constraint(equalTo: hourlyUIView.topAnchor).isActive = true
borderViewTop.heightAnchor.constraint(equalToConstant: 2).isActive = true
hourlyUIView.widthAnchor.constraint(equalToConstant: 160).isActive = true
hourlyUIView.heightAnchor.constraint(equalToConstant: 240).isActive = true
descriptionLabel.topAnchor.constraint(equalTo: hourlyUIView.topAnchor, constant: 16).isActive = true
descriptionLabel.centerXAnchor.constraint(equalTo: hourlyUIView.centerXAnchor, constant: 0).isActive = true
hourlyContentView.addSubview(hourlyUIView)
if previousHour == nil {
hourlyUIView.topAnchor.constraint(equalTo: hourlyContentView.topAnchor, constant: 0).isActive = true
hourlyUIView.leadingAnchor.constraint(equalTo: hourlyContentView.leadingAnchor, constant: 2).isActive = true
}
else {
hourlyUIView.topAnchor.constraint(equalTo: hourlyContentView.topAnchor, constant: 0).isActive = true
hourlyUIView.leadingAnchor.constraint(equalTo: previousHour!.trailingAnchor, constant: 0).isActive = true
borderView.bottomAnchor.constraint(equalTo: hourlyUIView.bottomAnchor).isActive = true
borderView.topAnchor.constraint(equalTo: hourlyUIView.topAnchor).isActive = true
borderView.widthAnchor.constraint(equalToConstant: 2).isActive = true
borderView.leadingAnchor.constraint(equalTo: hourlyUIView.leadingAnchor).isActive = true
}
previousHour = hourlyUIView
}
let borderViewTop = UIView()
let borderViewBottom = UIView()
borderViewTop.backgroundColor = .black
borderViewBottom.backgroundColor = .black
borderViewTop.translatesAutoresizingMaskIntoConstraints = false
borderViewBottom.translatesAutoresizingMaskIntoConstraints = false
hourlyScrollView.addSubview(hourlyContentView)
hourlyContentView.leadingAnchor.constraint(equalTo: hourlyScrollView.leadingAnchor, constant: 0).isActive = true
hourlyContentView.topAnchor.constraint(equalTo: hourlyScrollView.topAnchor, constant: 0).isActive = true
hourlyContentView.trailingAnchor.constraint(equalTo: hourlyScrollView.trailingAnchor, constant: 0).isActive = true
hourlyContentView.bottomAnchor.constraint(equalTo: hourlyScrollView.bottomAnchor, constant: 0).isActive = true
allContentView.addSubview(hourlyScrollView)
hourlyScrollView.isScrollEnabled = true
hourlyScrollView.topAnchor.constraint(equalTo: allContentView.topAnchor, constant: 20).isActive = true
hourlyScrollView.leadingAnchor.constraint(equalTo: allContentView.leadingAnchor, constant: 0).isActive = true
hourlyScrollView.trailingAnchor.constraint(equalTo: allContentView.trailingAnchor, constant: 0).isActive = true
}
create vertical scroll content
func layoutDailyViews() {
for subview in dailyContentView.subviews {
subview.removeFromSuperview()
}
var previousDay : UIView? = nil
for count in 1...10 {
let dailyUIView = UIView()
//dailyUIView.isUserInteractionEnabled = true
dailyUIView.tag = count
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dailyTap(_:)))
dailyUIView.addGestureRecognizer(tapGesture)
//hourlyUIView.frame.size = CGSize(width: 500, height: 50)
let descriptionLabel = UILabel()
dailyUIView.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.text = "daily test"
let borderView = UIView()
borderView.translatesAutoresizingMaskIntoConstraints = false
borderView.backgroundColor = .black
dailyUIView.addSubview(descriptionLabel)
dailyUIView.addSubview(borderView)
borderView.bottomAnchor.constraint(equalTo: dailyUIView.bottomAnchor).isActive = true
borderView.heightAnchor.constraint(equalToConstant: 2).isActive = true
borderView.leadingAnchor.constraint(equalTo: dailyUIView.leadingAnchor).isActive = true
borderView.trailingAnchor.constraint(equalTo: dailyUIView.trailingAnchor).isActive = true
dailyUIView.heightAnchor.constraint(equalToConstant: 100).isActive = true
descriptionLabel.leadingAnchor.constraint(equalTo: dailyUIView.leadingAnchor, constant: 16).isActive = true
descriptionLabel.centerYAnchor.constraint(equalTo: dailyUIView.centerYAnchor, constant: 0).isActive = true
dailyContentView.addSubview(dailyUIView)
if previousDay == nil {
dailyUIView.topAnchor.constraint(equalTo: dailyContentView.topAnchor, constant: 0).isActive = true
}
else {
dailyUIView.topAnchor.constraint(equalTo: previousDay!.bottomAnchor, constant: 0).isActive = true
}
dailyUIView.widthAnchor.constraint(equalToConstant: view.frame.width - 4).isActive = true
dailyUIView.centerXAnchor.constraint(equalTo: dailyContentView.centerXAnchor).isActive = true
previousDay = dailyUIView
}
allContentView.addSubview(dailyContentView)
}
func finishLayout() {
hourlyScrollView.bottomAnchor.constraint(equalTo: dailyContentView.bottomAnchor, constant: 0).isActive = true
dailyContentView.topAnchor.constraint(equalTo: allContentView.topAnchor, constant: 260).isActive = true
dailyContentView.centerXAnchor.constraint(equalTo: allContentView.centerXAnchor, constant: 0).isActive = true
dailyContentView.leadingAnchor.constraint(equalTo: allContentView.leadingAnchor).isActive = true
dailyContentView.trailingAnchor.constraint(equalTo: allContentView.trailingAnchor, constant: 0).isActive = true
dailyContentView.bottomAnchor.constraint(equalTo: allContentView.bottomAnchor).isActive = true
allScrollView.addSubview(allContentView)
allContentView.topAnchor.constraint(equalTo: allScrollView.topAnchor).isActive = true
allContentView.leadingAnchor.constraint(equalTo: allScrollView.leadingAnchor).isActive = true
allContentView.trailingAnchor.constraint(equalTo: allScrollView.trailingAnchor).isActive = true
allContentView.bottomAnchor.constraint(equalTo: allScrollView.bottomAnchor).isActive = true
allContentView.centerXAnchor.constraint(equalTo: allScrollView.centerXAnchor).isActive = true
allContentView.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
allContentView.heightAnchor.constraint(equalToConstant: 1500).isActive = true
view.addSubview(allScrollView)
allScrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
allScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
allScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
allScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
tapped functions
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
hourlyScrollView.contentSize = CGSize(width:160 * 10 + 2, height:240)
allScrollView.contentSize = CGSize(width: view.frame.width, height:1500)
}
#objc func hourlyTap(_ sender: UITapGestureRecognizer) {
let tappedView = sender.view
print("hourly: \(tappedView!.tag)")
}
#objc func dailyTap(_ sender: UITapGestureRecognizer) {
let tappedView = sender.view
print("daily: \(tappedView!.tag)")
}
You haven't set all the required constraints on your hourlyContentView so the horizontal scrollView's size is (0,0) and as such it can't be scrolled or tapped. You can use Debug View Hierarchy in Xcode to see this.
The constraints you need to add are:
Between your last hourlyUIView's trailingAnchor and hourlyContentView's trailing anchor:
...
previousHour = hourlyUIView
}
previousHour?.trailingAnchor.constraint(equalTo: hourlyContentView.trailingAnchor).isActive = true
let borderViewTop = UIView()
let borderViewBottom = UIView()
...
Setting your hourlyContentView heightAnchor equal to the hourlyScrollView height anchor:
hourlyContentView.heightAnchor.constraint(equalTo: hourlyScrollView.heightAnchor).isActive = true
I am working on a "Profile View Controller" which is inside a TableViewCell and table cell dimension is set as UITableView.automaticDimension:
The problem is that I would like to set the background image view (Blue) with a variable height based on cell width and a 16:9 ratio. For some reason I am not being able to change the view height even if I set the constant.
Here the code:
let topView : UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = 20
view.backgroundColor = .yoofitDarkBlue
view.layer.masksToBounds = true
view.layer.shadowColor = UIColor.lightGray.cgColor
view.layer.borderWidth = 0.5
view.layer.borderColor = UIColor.yoofitDarkBlue.cgColor
view.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
view.layer.shadowRadius = 12.0
view.layer.shadowOpacity = 0.7
return view
}()
let userImage : UIImageView = {
let i = UIImageView()
i.translatesAutoresizingMaskIntoConstraints = false
i.image = UIImage(named: "user2")
i.layer.masksToBounds = true
i.layer.cornerRadius = 75
i.layer.borderWidth = 1
i.layer.borderColor = UIColor.white.cgColor
return i
}()
var userNameLabel:UILabel = {
let l = UILabel()
l.translatesAutoresizingMaskIntoConstraints = false
l.font = UIFont(name: "AvenirNext-DemiBold", size: 20)
l.textAlignment = .center
l.textColor = .yoofitBlack
return l
}()
func setupViews() {
self.backgroundColor = .clear
self.selectionStyle = .none
addSubview(topView)
let width = self.frame.width
print(width) // print 320
topView.topAnchor.constraint(equalTo: topAnchor, constant: 10).isActive = true
topView.leftAnchor.constraint(equalTo: leftAnchor, constant: 8).isActive = true
topView.rightAnchor.constraint(equalTo: rightAnchor, constant: -8).isActive = true
topView.heightAnchor.constraint(equalToConstant: width/16*9).isActive = true // this doesn't work even if I set another number like 600
topView.layoutIfNeeded()
addSubview(userImage)
userImage.centerYAnchor.constraint(equalTo: topView.bottomAnchor).isActive = true
userImage.centerXAnchor.constraint(equalTo: topView.centerXAnchor).isActive = true
userImage.widthAnchor.constraint(equalToConstant: 150).isActive = true
userImage.heightAnchor.constraint(equalToConstant: 150).isActive = true
addSubview(userNameLabel)
userNameLabel.topAnchor.constraint(equalTo: userImage.bottomAnchor, constant: 10).isActive = true
userNameLabel.centerXAnchor.constraint(equalTo: userImage.centerXAnchor).isActive = true
userNameLabel.widthAnchor.constraint(equalToConstant: 200).isActive = true
userNameLabel.heightAnchor.constraint(equalToConstant: 20).isActive = true
userNameLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -20).isActive = true
}
PLEASE NOTE THERE ARE 2 answers to this question. The latter is definitely the correct one but the first maybe may help others.
So this is how I fixed it but I hope to get better answers. This answer helped me to go to the right path (iOS: How to Align The Center of a View With The Bottom of Another View With AutoLayout)
I have added a containing view which is twice as the required size of my top view (the blue one).
I centered the picture on the containing view.
self.conteiningView.backgroundColor = .red // I made this red so you can visually see how the views are related to each other
let width = self.frame.width
self.addSubview(conteiningView)
conteiningView.topAnchor.constraint(equalTo: topAnchor, constant: 8).isActive = true
conteiningView.leftAnchor.constraint(equalTo: leftAnchor, constant: 8).isActive = true
conteiningView.rightAnchor.constraint(equalTo: rightAnchor, constant: -8).isActive = true
conteiningView.heightAnchor.constraint(equalToConstant: (width/16*9)*2).isActive = true // twice of the blue view
conteiningView.layoutIfNeeded()
self.conteiningView.addSubview(topView)
topView.topAnchor.constraint(equalTo: conteiningView.topAnchor).isActive = true
topView.leftAnchor.constraint(equalTo: conteiningView.leftAnchor).isActive = true
topView.rightAnchor.constraint(equalTo: conteiningView.rightAnchor).isActive = true
topView.heightAnchor.constraint(equalToConstant: width/16*9).isActive = true // 16:9 ration
conteiningView.addSubview(userImage)
userImage.centerYAnchor.constraint(equalTo: conteiningView.centerYAnchor).isActive = true
userImage.centerXAnchor.constraint(equalTo: conteiningView.centerXAnchor).isActive = true
userImage.widthAnchor.constraint(equalToConstant: width/2).isActive = true
userImage.heightAnchor.constraint(equalToConstant: width/2).isActive = true
userImage.layer.cornerRadius = width/4 // to mantain nice proportions
conteiningView.addSubview(userNameLabel)
userNameLabel.topAnchor.constraint(equalTo: userImage.bottomAnchor, constant: 10).isActive = true
userNameLabel.centerXAnchor.constraint(equalTo: userImage.centerXAnchor).isActive = true
userNameLabel.widthAnchor.constraint(equalToConstant: 200).isActive = true
userNameLabel.heightAnchor.constraint(equalToConstant: 20).isActive = true
With red background:
With clear background:
UPDATE: The answer above works but I have actually found the problem:
Even if I had set:
self.tableView.rowHeight = UITableView.automaticDimension
self.tableView.estimatedRowHeight = 300
For some (silly me) I had also implemented:
tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
This, of course, does not be implemented for the automatic dimension to work.
removing that allowed to use the following code to achieve the same result but without setting a predefined height:
self.addSubview(conteiningView)
conteiningView.topAnchor.constraint(equalTo: topAnchor, constant: 8).isActive = true
conteiningView.leftAnchor.constraint(equalTo: leftAnchor, constant: 8).isActive = true
conteiningView.rightAnchor.constraint(equalTo: rightAnchor, constant: -8).isActive = true
conteiningView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
conteiningView.layoutIfNeeded()
self.conteiningView.addSubview(topView)
topView.topAnchor.constraint(equalTo: conteiningView.topAnchor).isActive = true
topView.leftAnchor.constraint(equalTo: conteiningView.leftAnchor).isActive = true
topView.rightAnchor.constraint(equalTo: conteiningView.rightAnchor).isActive = true
topView.heightAnchor.constraint(equalToConstant: width/16*9).isActive = true
conteiningView.addSubview(userImage)
userImage.centerYAnchor.constraint(equalTo: topView.bottomAnchor).isActive = true // the vertical center is now set nicely at bottom edge of my top view.
userImage.centerXAnchor.constraint(equalTo: topView.centerXAnchor).isActive = true
userImage.widthAnchor.constraint(equalToConstant: width/2).isActive = true
userImage.heightAnchor.constraint(equalToConstant: width/2).isActive = true
userImage.layer.cornerRadius = width/4
conteiningView.addSubview(userNameLabel)
userNameLabel.topAnchor.constraint(equalTo: userImage.bottomAnchor, constant: 2).isActive = true
userNameLabel.centerXAnchor.constraint(equalTo: userImage.centerXAnchor).isActive = true
userNameLabel.widthAnchor.constraint(equalToConstant: 200).isActive = true
userNameLabel.heightAnchor.constraint(equalToConstant: 35).isActive = true
what i am trying to do is simple. let me explain what i have first, in the mainviewcontroller i have 3 main view at the beginning navbar, content,and bottombtn. i have a sidebar btn that then trigger a function in the mainviewcontroller, each function is suppose to remove the middle view (the content) and then place a new subview to take the content place.
the problem: it work at first the function delete contentTxt and replace it with one of the new view example: connectView, but the problem is when i try to trigger another function let say addAchievementView() it will not delete connectView and then add achievementview instead it let add achievementview below the connect View
my Goal: is for the function to delete the previous view(whichever view that is taking the contentplace) and then adding a new view. is there a way to get around this? or is there a better way to do this?
here is the mainViewController code:
class mainViewController: UIViewController {
let navbar:navbarView = {
let content = navbarView()
return content
}()
let contentTxt:UITextView = {
let content = UITextView()
content.backgroundColor = UIColor.green
content.font = UIFont(name: "copperplate", size: 20)
return content
}()
let bottomBtn:UIButton = {
let content = UIButton()
content.backgroundColor = UIColor.blue
return content
}()
override func viewDidLoad() {
super.viewDidLoad()
navbar.translatesAutoresizingMaskIntoConstraints = false
contentTxt.translatesAutoresizingMaskIntoConstraints = false
bottomBtn.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(navbar)
view.addSubview(contentTxt)
view.addSubview(bottomBtn)
navbar.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
navbar.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
navbar.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
navbar.heightAnchor.constraint(equalToConstant: 50).isActive = true
contentTxt.topAnchor.constraint(equalTo: navbar.bottomAnchor, constant: 5).isActive = true
contentTxt.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
contentTxt.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
contentTxt.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
bottomBtn.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant:-10).isActive = true
bottomBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
bottomBtn.widthAnchor.constraint(equalToConstant: 70).isActive = true
bottomBtn.heightAnchor.constraint(equalToConstant: 70).isActive = true
}
#objc func addConnectView(){
print("addConnectView")
self.contentTxt.removeFromSuperview()
let connect:connectView = {
let content = connectView()
content.backgroundColor = UIColor.red
return content
}()
connect.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(connect)
self.view.sendSubview(toBack: connect)
connect.topAnchor.constraint(equalTo: navbar.bottomAnchor, constant: 5).isActive = true
connect.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
connect.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
connect.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
}
#objc func addTemplateView(){
print("addTemplateView")
self.contentTxt.removeFromSuperview()
let content:templateView = {
let content = templateView()
content.backgroundColor = UIColor.blue
return content
}()
content.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(content)
self.view.sendSubview(toBack: content)
content.topAnchor.constraint(equalTo: navbar.bottomAnchor, constant: 5).isActive = true
content.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
content.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
content.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
}
#objc func addSettingView(){
print("addSettingView")
self.contentTxt.removeFromSuperview()
let content:settingView = {
let content = settingView()
content.backgroundColor = UIColor.green
return content
}()
content.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(content)
self.view.sendSubview(toBack: content)
content.topAnchor.constraint(equalTo: navbar.bottomAnchor, constant: 5).isActive = true
content.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
content.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
content.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
}
#objc func addAchievementView(){
print("addAchievementView")
self.contentTxt.removeFromSuperview()
let content:achievementView = {
let content = achievementView()
content.backgroundColor = UIColor.gray
return content
}()
content.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(content)
self.view.sendSubview(toBack: content)
content.topAnchor.constraint(equalTo: navbar.bottomAnchor, constant: 5).isActive = true
content.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
content.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
content.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
}
#objc func addCommandView(){
print("addCommandView")
self.contentTxt.removeFromSuperview()
let content:commandView = {
let content = commandView()
content.backgroundColor = UIColor.cyan
return content
}()
content.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(content)
self.view.sendSubview(toBack: content)
content.topAnchor.constraint(equalTo: navbar.bottomAnchor, constant: 5).isActive = true
content.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
content.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
content.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
}
#objc func addListView(){
print("addListView")
self.contentTxt.removeFromSuperview()
let content:commandView = {
let content = commandView()
content.backgroundColor = UIColor.red
return content
}()
content.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(content)
self.view.sendSubview(toBack: content)
content.topAnchor.constraint(equalTo: navbar.bottomAnchor, constant: 5).isActive = true
content.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
content.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
content.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
}
#objc func addNavbarView(){
print("addNavbarView")
self.contentTxt.removeFromSuperview()
let content:navbarListView = {
let content = navbarListView()
content.backgroundColor = UIColor.red
return content
}()
content.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(content)
self.view.sendSubview(toBack: content)
content.topAnchor.constraint(equalTo: navbar.bottomAnchor, constant: 5).isActive = true
content.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
content.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
content.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
}
#objc func sideController(){
let next = self.storyboard?.instantiateViewController(withIdentifier: "sideViewController") as! sideViewController
self.present(next, animated: true, completion: nil)
}
#objc func profileController(){
let next = self.storyboard?.instantiateViewController(withIdentifier: "profileViewController") as! profileViewController
self.present(next, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Before add any view make sure to remove all other , as you don't know what is currently displayed so
self.contentTxt.removeFromSuperview()
self.content.removeFromSuperview() //
self.content.removeFromSuperview() // for settings
Also this line is the problem
self.view.sendSubview(toBack: content)
as by default the added view is placed above all childs of the parentView
I vote for creating placeHolderView and remove it's subviews before any addition , this will prevent headache of knowing which one is currently displayed , or you may give a tag to any added view and do this before any new addition
self.view.subviews.forEach { if $0.tag == 11 {
$0.removeFromSuperview()
}}
Views were placed using code.
If I press deleteButton (button), I want the hidden button(imgButton) to appear.
However, imgView's width is not refresh.
MainViewController.swift
import UIKit
class MainViewController: UIViewController {
var trashIsSelected: Bool!
let imgButton: UIButton = {
let imgView = UIButton()
imgView.setImage(UIImage(named: "schedule_delete_icon"), for: UIControlState.normal)
// imgView.imageView?.image = UIImage(named: "schedule_delete_icon")
imgView.translatesAutoresizingMaskIntoConstraints = false
return imgView
}()
let deleteButton: UIButton = {
let imgBtn = UIButton()
imgBtn.setImage(UIImage(named: "icon_delete"), for: UIControlState.normal)
// imgBtn.imageView?.image = UIImage(named: "icon_delete")
imgBtn.translatesAutoresizingMaskIntoConstraints = false
return imgBtn
}()
let label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "하ㅣㅇ하이히아히아하하하하ㅏㅎ하ㅏㅎ하ㅏ하하하하ㅏㅏ하하하하하ㅏ"
return label
}()
var imgViewWidth: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
setupLayout()
}
func setupLayout(){
let testView = UIScrollView()
self.view.addSubview(testView)
testView.backgroundColor = .lightGray
testView.translatesAutoresizingMaskIntoConstraints = false
testView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
testView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
testView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
testView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.3).isActive = true
testView.addSubview(imgButton)
testView.addSubview(label)
imgButton.leadingAnchor.constraint(equalTo: testView.leadingAnchor, constant: 10).isActive = true
imgButton.centerYAnchor.constraint(equalTo: testView.centerYAnchor).isActive = true
imgButton.heightAnchor.constraint(equalTo: testView.heightAnchor, multiplier: 0.2).isActive = true
imgButton.widthAnchor.constraint(equalTo: imgButton.heightAnchor, multiplier: 0).isActive = true
imgButton.isHidden = true
trashIsSelected = false
label.centerYAnchor.constraint(equalTo: testView.centerYAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: imgButton.trailingAnchor, constant: 10).isActive = true
label.heightAnchor.constraint(equalTo: testView.heightAnchor, multiplier: 0.2).isActive = true
label.widthAnchor.constraint(equalTo: testView.widthAnchor, multiplier: 0.5).isActive = true
self.view.addSubview(deleteButton)
deleteButton.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
deleteButton.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
deleteButton.addTarget(self, action: #selector(self.addBtnAction(_:)), for: UIControlEvents.touchUpInside)
}
#objc func addBtnAction(_ sender: UIButton){
print("hi")
if trashIsSelected == false{
trashIsSelected = true
imgButton.isHidden = false
imgButton.widthAnchor.constraint(equalToConstant: 50).isActive = true
imgButton.updateConstraints()
}else{
trashIsSelected = false
imgButton.widthAnchor.constraint(equalToConstant: 0).isActive = true
imgButton.isHidden = true
imgButton.updateConstraints()
}
}
}
This is error message:
2018-05-23 14:00:47.697959+0900 Test[67488:4887863] [LayoutConstraints] Unable 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.
(
"",
""
)
Will attempt to recover by breaking constraint
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in may also be helpful.
You are adding new constraints to the button that conflict with the old ones (how can a button be 0 points wide, and simultaneously 50 points wide?). To make it work, you need to turn off the old constraint before you activate a new one. I recommend creating a property that would keep the current imgButton constraint at all times, and then when you want to change it, just use that (either turn it off and create a new one, or just set a constant, which in your case is better and easier):
import UIKit
class MainViewController: UIViewController {
// property referencing current imgButton width constraint
fileprivate var imgButtonWidthConstraint: NSLayoutConstraint!
var trashIsSelected: Bool!
let imgButton: UIButton = {
let imgView = UIButton()
imgView.setImage(UIImage(named: "schedule_delete_icon"), for: UIControlState.normal)
// imgView.imageView?.image = UIImage(named: "schedule_delete_icon")
imgView.translatesAutoresizingMaskIntoConstraints = false
return imgView
}()
let deleteButton: UIButton = {
let imgBtn = UIButton()
imgBtn.setImage(UIImage(named: "icon_delete"), for: UIControlState.normal)
// imgBtn.imageView?.image = UIImage(named: "icon_delete")
imgBtn.translatesAutoresizingMaskIntoConstraints = false
return imgBtn
}()
let label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "하ㅣㅇ하이히아히아하하하하ㅏㅎ하ㅏㅎ하ㅏ하하하하ㅏㅏ하하하하하ㅏ"
return label
}()
var imgViewWidth: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
setupLayout()
}
func setupLayout(){
let testView = UIScrollView()
self.view.addSubview(testView)
testView.backgroundColor = .lightGray
testView.translatesAutoresizingMaskIntoConstraints = false
testView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
testView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
testView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
testView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.3).isActive = true
testView.addSubview(imgButton)
testView.addSubview(label)
imgButton.leadingAnchor.constraint(equalTo: testView.leadingAnchor, constant: 10).isActive = true
imgButton.centerYAnchor.constraint(equalTo: testView.centerYAnchor).isActive = true
imgButton.heightAnchor.constraint(equalTo: testView.heightAnchor, multiplier: 0.2).isActive = true
// keep the reference to constraint that defines width
// (we will use the constraint setting the width to constant, since then you can
// simply switch the constant between 0 and 50):
imgButtonWidthConstraint = imgButton.widthAnchor.constraint(equalToConstant: 0)
imgButtonWidthConstraint.isActive = true
imgButton.isHidden = true
trashIsSelected = false
label.centerYAnchor.constraint(equalTo: testView.centerYAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: imgButton.trailingAnchor, constant: 10).isActive = true
label.heightAnchor.constraint(equalTo: testView.heightAnchor, multiplier: 0.2).isActive = true
label.widthAnchor.constraint(equalTo: testView.widthAnchor, multiplier: 0.5).isActive = true
self.view.addSubview(deleteButton)
deleteButton.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
deleteButton.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
deleteButton.addTarget(self, action: #selector(self.addBtnAction(_:)), for: UIControlEvents.touchUpInside)
}
#objc func addBtnAction(_ sender: UIButton){
print("hi")
if trashIsSelected == false{
trashIsSelected = true
imgButton.isHidden = false
// just change the constant to what you want
imgButtonWidthConstraint.constant = 50
imgButton.updateConstraints()
} else {
trashIsSelected = false
imgButtonWidthConstraint.constant = 0
imgButton.isHidden = true
imgButton.updateConstraints()
}
}
}
EDIT:
Just for completeness of the answer, if you were for some reason using constraints where changing a constant would not be enough, you would have to activate and deactivate the constraints. E.g., if you were using multiplier to determine imgButton's width, you would have to use this approach (multiplier is an immutable property of the NSLayoutConstraint). So therefore creating a constraint:
// simply switch the constant between 0 and 50):
imgButtonWidthConstraint = imgButton.widthAnchor.constraint(equalTo: someOtherView.widthAnchor, multiplier: 0)
imgButtonWidthConstraint.isActive = true
And then in addBtnAction you would have to do to this:
#objc func addBtnAction(_ sender: UIButton){
print("hi")
if trashIsSelected == false{
trashIsSelected = true
imgButton.isHidden = false
// first deactivate current constraint
imgButtonWidthConstraint.isActive = false
// then create a new one and store it to imgButtonWidthConstraint property (the old one is deactivated, so you don't need a reference to it anymore)
imgButtonWidthConstraint = imgButton.widthAnchor.constraint(equalTo: someOtherView.widthAnchor, multiplier: 0.75)
// and activate the new one
imgButtonWidthConstraint.isActive = true
imgButton.updateConstraints()
} else {
trashIsSelected = false
// same process again
imgButtonWidthConstraint.isActive = false
imgButtonWidthConstraint = imgButton.widthAnchor.constraint(equalTo: someOtherView.widthAnchor, multiplier: 0)
imgButtonWidthConstraint.isActive = true
imgButton.isHidden = true
imgButton.updateConstraints()
}
}
So I have a pretty simple layout for a view that I have created, basically what i want it to look like after I'm done with adding constraints is as follows,
However, what I end up with is something else, and Im not sure why this behavior is happening.
So just a quick rundown of what I did in an attempt to achieve the layouts I wanted.
Center the X position of the "/" label
Set the the indexLabel that can be seen towards the left that says "1"
Constraint the "reps" label to the left of "/" label
Finally constraint the "reps field" to the right of indexLabel and left of "reps" label
private func setupDividerLabelLayout() {
addSubview(dividerLabel)
dividerLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
dividerLabel.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
}
private func setupIndexLabelBackgroundLayout() {
addSubview(indexLabelBackground)
indexLabelBackground.leftAnchor.constraint(equalTo: leftAnchor, constant: 24).isActive = true
indexLabelBackground.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
indexLabelBackground.heightAnchor.constraint(equalToConstant: 24).isActive = true
indexLabelBackground.widthAnchor.constraint(equalToConstant: 24).isActive = true
}
private func setupRepsLabelLayout() {
addSubview(repsLabel)
repsLabel.rightAnchor.constraint(equalTo: dividerLabel.leftAnchor, constant: -16).isActive = true
repsLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
}
private func setupRepsFieldLayout() {
addSubview(repsField)
repsField.rightAnchor.constraint(equalTo: repsLabel.leftAnchor, constant: -8).isActive = true
repsField.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
repsField.leftAnchor.constraint(equalTo: indexLabelBackground.rightAnchor, constant: 8).isActive = true
}
In order let you anchors work you should add _ViewName_.translatesAutoresizingMaskIntoConstraints = false. so the code becomes as followsCode to Use
private func setupDividerLabelLayout() {
addSubview(dividerLabel)
dividerLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
dividerLabel.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
dividerLabel.translatesAutoresizingMaskIntoConstraints = false
}
private func setupIndexLabelBackgroundLayout() {
addSubview(indexLabelBackground)
indexLabelBackground.leftAnchor.constraint(equalTo: leftAnchor, constant: 24).isActive = true
indexLabelBackground.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
indexLabelBackground.heightAnchor.constraint(equalToConstant: 24).isActive = true
indexLabelBackground.widthAnchor.constraint(equalToConstant: 24).isActive = true
indexLabelBackground.translatesAutoresizingMaskIntoConstraints = false
}
private func setupRepsLabelLayout() {
addSubview(repsLabel)
repsLabel.rightAnchor.constraint(equalTo: dividerLabel.leftAnchor, constant: -16).isActive = true
repsLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
repsLabel.translatesAutoresizingMaskIntoConstraints = false
}
private func setupRepsFieldLayout() {
addSubview(repsField)
repsField.rightAnchor.constraint(equalTo: repsLabel.leftAnchor, constant: -8).isActive = true
repsField.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
repsField.leftAnchor.constraint(equalTo:
indexLabelBackground.rightAnchor, constant: 8).isActive = true
repsField.translatesAutoresizingMaskIntoConstraints = false
indexLabelBackground.translatesAutoresizingMaskIntoConstraints = false
}