WishIHadThreeGuns
WishIHadThreeGuns

Reputation: 1469

Unexpected frame of subview (Swift)

My code displays my view initialview as a subview of the container containerView.

I'm expecting initialView.frame to be the frame in the coordinates of the superview (that is the containerview) - which is reported int he playground to be (0,0,0,0) - but it is then displayed in the container so how can the width and height possibly be zero, as reported?

enter image description here

The playground code -

final class InitialView: UIView {
    let traverseButton = UIButton(type: .custom)
    let networkButton = UIButton(type: .custom)
    let networkLabel = UILabel()
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setup() {
        self.backgroundColor = .red
        traverseButton.frame = CGRect(x: 0, y: 0, width: 200, height: 100)
        traverseButton.setTitle("Go to Detail", for: .normal)
        traverseButton.setTitleColor(.black, for: .normal)
        traverseButton.isUserInteractionEnabled = true

        self.addSubview(traverseButton)
        traverseButton.translatesAutoresizingMaskIntoConstraints = false
        traverseButton.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
        traverseButton.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true

        networkButton.frame = CGRect(x: 0, y: 0, width: 200, height: 100)
        networkButton.setTitle("Make Network Call", for: .normal)
        networkButton.setTitleColor(.black, for: .normal)
        networkButton.isUserInteractionEnabled = true

        self.addSubview(networkButton)
        networkButton.translatesAutoresizingMaskIntoConstraints = false
        networkButton.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
        networkButton.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 100).isActive = true

        networkLabel.text = "No network calls made"
        networkLabel.backgroundColor = .purple
        self.addSubview(networkLabel)

        networkLabel.translatesAutoresizingMaskIntoConstraints = false
        networkLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
        networkLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 200).isActive = true
        networkLabel.widthAnchor.constraint(equalToConstant: 300).isActive = true
        networkLabel.heightAnchor.constraint(equalToConstant: 100).isActive = true
    }

    func setNetworkLabel(text: String){
        networkLabel.text = text
    }
}

var initialView: InitialView?
initialView = InitialView()

let containerView = UIView(frame: CGRect(x: 10, y: 0, width: 500, height: 1000))
containerView.addSubview(initialView!)

initialView?.translatesAutoresizingMaskIntoConstraints = false

initialView?.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
initialView?.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
initialView?.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
initialView?.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true

Upvotes: 1

Views: 474

Answers (1)

Sweeper
Sweeper

Reputation: 270770

You have probably put the initialView?.frame line before the containerView line.

Although you have added the constraints, before Xcode playgrounds actually renders the containerView, its subviews are not laid out. That's why initialView's frame remains at its default value of (0, 0, 0, 0). If you actually manually tell containerView that it should lay out its subviews, initialView's frame will be set correctly.

There are many ways to do this:

  • move the line where you inspect initialView?.frame after the line where you inspect containerView
  • call containerView.setNeedsLayout() first
  • call containerView.layoutIfNeeded() first

Upvotes: 2

Related Questions