PureLayout icon indicating copy to clipboard operation
PureLayout copied to clipboard

Button not working when its superview is auto centered

Open lmsmartins opened this issue 6 years ago • 3 comments
trafficstars

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:

Screenshot 2019-08-12 at 15 34 23

lmsmartins avatar Aug 12 '19 15:08 lmsmartins

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)

lmsmartins avatar Aug 12 '19 15:08 lmsmartins

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).

toohotz avatar Aug 12 '19 18:08 toohotz

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?

lmsmartins avatar Aug 13 '19 09:08 lmsmartins