PureLayout
PureLayout copied to clipboard
Button not working when its superview is auto centered
Hi,
I've created a custom view that contains 2 labels and a button. When I set the custom view to be auto centered in its superview, I can no longer tap the button.
Here's the code I'm using to init the view and add it to a view controller inside the viewDidLoad function:
let errorView = ErrorView(frame: CGRect(x: 120, y: 150, width: 100, height: 100))
self.view.addSubview(errorView)
errorView.autoCenterInSuperview() // ---> This is the problematic line.
This is the custom view class:
import UIKit
import PureLayout
class ErrorView: UIView {
var contentView: UIView!
var titleLabel: UILabel!
var subTitleLabel: UILabel!
var tryAgainButton: UIButton!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
public func setup() {
contentView = UIView()
contentView.backgroundColor = .red
contentView.widthAnchor.constraint(lessThanOrEqualToConstant: 300).isActive = true
contentView.heightAnchor.constraint(lessThanOrEqualToConstant: 200).isActive = true
self.addSubview(contentView)
contentView.autoCenterInSuperview()
titleLabel = UILabel()
titleLabel.backgroundColor = .green
titleLabel.font = UIFont.preferredFont(forTextStyle: .title2)
titleLabel.adjustsFontForContentSizeCategory = true
titleLabel.text = "Failed to load this screen"
contentView.addSubview(titleLabel)
titleLabel.textAlignment = .center
titleLabel.autoAlignAxis(.vertical, toSameAxisOf: contentView)
titleLabel.autoPinEdge(.top, to: .top, of: contentView, withOffset: 16)
titleLabel.autoPinEdge(.left, to: .left, of: contentView, withOffset: 16)
titleLabel.autoPinEdge(.right, to: .right, of: contentView, withOffset: -16)
subTitleLabel = UILabel()
subTitleLabel.backgroundColor = .cyan
subTitleLabel.font = UIFont.preferredFont(forTextStyle: .body)
subTitleLabel.adjustsFontForContentSizeCategory = true
subTitleLabel.text = "Please contact support."
contentView.addSubview(subTitleLabel)
subTitleLabel.textAlignment = .center
subTitleLabel.autoAlignAxis(.vertical, toSameAxisOf: contentView)
subTitleLabel.autoPinEdge(.top, to: .bottom, of: titleLabel, withOffset: 16)
subTitleLabel.autoPinEdge(.left, to: .left, of: titleLabel, withOffset: 16)
subTitleLabel.autoPinEdge(.right, to: .right, of: titleLabel, withOffset: -16)
tryAgainButton = UIButton(type: .system)
tryAgainButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline)
tryAgainButton.titleLabel?.adjustsFontForContentSizeCategory = true
tryAgainButton.frame = CGRect(x: 0, y: 0, width: 10, height: 50)
tryAgainButton.backgroundColor = .white
tryAgainButton.setTitle("Try again", for: .normal)
tryAgainButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
contentView.addSubview(tryAgainButton)
tryAgainButton.autoAlignAxis(.vertical, toSameAxisOf: contentView)
tryAgainButton.autoPinEdge(.top, to: .bottom, of: subTitleLabel, withOffset: 16)
}
@objc func buttonAction() {
print("****** clickable")
}
}
What could be the issue here? Is this a library bug? Or did I configured anything wrong? This is how the view looks:

The same issue happens when using the following statements to center the custom view in the view controller's view:
errorView.autoAlignAxis(.horizontal, toSameAxisOf: self.view)
errorView.autoAlignAxis(.vertical, toSameAxisOf: self.view)
The -[autoCenterInSuperview] deals with aligning the axis to the superview axis x and so once your subviews have their internal constraints setup correctly, the view should center without a problem which it is doing though the button seems to be the issue but that maybe related to how you're setting the frame of the button and also using Autolayout via PureLayout to setup its positioning.
So I noticed that you're setting the frame of the button like so tryAgainButton.frame = CGRect(x: 0, y: 0, width: 10, height: 50), I'm not actively at a machine to run this code in Xcode but I'm curious to see why you're setting the width and height explicitly through frames vs just doing tryAgainButton.autoSetDimention(CGSize: size) where you can then do your 10 and 50 as you have specified. I'm assuming the touch target size for the button is not large enough possibly.
With the content view you can also set the height and width anchor using PureLayout by doing contentView.autoSetDimension(.width, toSize: 300, relation: .lessThanOrEqual).
Thanks for your input @toohotz I've performed the changes you mentioned, but unfortunately, I'm not able to get the button working when auto centering its super view. I also changed the size of the button, it wasn't supposed to have a width of 10. Nonetheless, I'm still having issues to get the button working when auto centering its super view.
Here's the ErrorView class code:
import UIKit
import PureLayout
class ErrorView: UIView {
var contentView: UIView!
var titleLabel: UILabel!
var subTitleLabel: UILabel!
var tryAgainButton: UIButton!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
public func setup() {
contentView = UIView()
contentView.backgroundColor = .red
contentView.autoSetDimension(.width, toSize: 300, relation: .lessThanOrEqual)
contentView.autoSetDimension(.height, toSize: 200, relation: .lessThanOrEqual)
self.addSubview(contentView)
contentView.autoCenterInSuperview()
titleLabel = UILabel()
titleLabel.backgroundColor = .green
titleLabel.font = UIFont.preferredFont(forTextStyle: .title2)
titleLabel.adjustsFontForContentSizeCategory = true
titleLabel.text = "Failed to load this screen"
contentView.addSubview(titleLabel)
titleLabel.textAlignment = .center
titleLabel.autoAlignAxis(.vertical, toSameAxisOf: contentView)
titleLabel.autoPinEdge(.top, to: .top, of: contentView, withOffset: 16)
titleLabel.autoPinEdge(.left, to: .left, of: contentView, withOffset: 16)
titleLabel.autoPinEdge(.right, to: .right, of: contentView, withOffset: -16)
subTitleLabel = UILabel()
subTitleLabel.backgroundColor = .cyan
subTitleLabel.font = UIFont.preferredFont(forTextStyle: .body)
subTitleLabel.adjustsFontForContentSizeCategory = true
subTitleLabel.text = "Please contact support."
contentView.addSubview(subTitleLabel)
subTitleLabel.textAlignment = .center
subTitleLabel.autoAlignAxis(.vertical, toSameAxisOf: contentView)
subTitleLabel.autoPinEdge(.top, to: .bottom, of: titleLabel, withOffset: 16)
subTitleLabel.autoPinEdge(.left, to: .left, of: titleLabel, withOffset: 16)
subTitleLabel.autoPinEdge(.right, to: .right, of: titleLabel, withOffset: -16)
tryAgainButton = UIButton(type: .system)
tryAgainButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline)
tryAgainButton.titleLabel?.adjustsFontForContentSizeCategory = true
tryAgainButton.autoSetDimensions(to: CGSize(width: 90, height: 40))
tryAgainButton.backgroundColor = .white
tryAgainButton.setTitle("Try again", for: .normal)
tryAgainButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
contentView.addSubview(tryAgainButton)
tryAgainButton.autoAlignAxis(.vertical, toSameAxisOf: contentView)
tryAgainButton.autoPinEdge(.top, to: .bottom, of: subTitleLabel, withOffset: 16)
}
@objc func buttonAction() {
print("****** clickable")
}
}
This is the VC code that displays the custom error view:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let errorView = ErrorView(frame: CGRect(x: 0, y: 0, width: 300, height: 200))
self.view.addSubview(errorView)
// When removing the statement below, the button becomes clickable.
errorView.autoCenterInSuperview()
}
Is there anything else you think I might be missing?