Search code examples
swiftautolayoutuikitnslayoutconstraint

Auto-Layout, layout constraints producing puzzling results UIKit Swift 5


I am currently getting to grips with UIKit and trying to build a simple game to do so. The first part I am struggling to understanding is auto layout, the necessary constraints and their behaviour, as well as view hierarchy.

Here is a basic UIViewController that is simply trying to place a game board (UIImageView) onto its root view.

class GameView {

    var gameBoard: UIImageView = UIImageView(image: UIImage(named: "grid"))

}




class SinglePlayerGameViewController: UIViewController {
    
    var gameModel: GameModel = GameModel()
    var gameView: GameView = GameView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.setUpGameBoard()
        //self.startGame()
    }
    
    private func setUpGameBoard() -> Void {
        print("screen size", UIScreen.main.bounds.size)
        self.gameView.gameBoard.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(self.gameView.gameBoard)
        self.gameView.gameBoard.contentMode = .scaleAspectFit
        self.gameView.gameBoard.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        print("vc center X", self.view.center.x)
        print("gb center X", self.gameView.gameBoard.center.x)
        self.gameView.gameBoard.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        print("vc center Y", self.view.center.y)
        print("gb center Y", self.gameView.gameBoard.center.y)
        self.gameView.gameBoard.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.9).isActive = true
        print("vc width bounds", self.view.bounds.size.width)
        print("vc width frame", self.view.frame.size.width)
        print("gb width bounds", self.gameView.gameBoard.bounds.size.width)
        print("gb width frame", self.gameView.gameBoard.bounds.size.width)
        
    }
    
}

The output of the print statements below is as follows:

screen size (428.0, 926.0)
vc center X 214.0
gb center X 375.0
vc center Y 463.0
gb center Y 500.0
vc width bounds 428.0
vc width frame 428.0
gb width bounds 750.0
gb width frame 750.0

What confuses me is the following:

  1. According to the quick help in Xcode, the centerXAnchor is defined as: A layout anchor representing the horizontal center of the view’s frame. So I am struggling to understand why the output for center x-coordinates for the parent view and the game board is different? The same thing goes for the center y-coordinate.

  2. The widthAnchor is defined as: A layout anchor representing the width of the view’s frame.. So I would think that applying the multiplier of .9 would result in the width of my game board being exactly 90% of the parent view's frame, but that doesn't seem to be the case here and I can't really see why.

The funny thing is that the simulator is still displaying it properly, like so:

enter image description here

If there is anyone that could shed some light on this, I would very much appreciate it!

Thanks


Solution

  • Because you are doing your print statements in viewDidLoad which is before your autolayout constraints have taken effect. You can create constraints there, but they are not applied fully until layout time. Move all the print statements into viewDidLayoutSubviews, keeping everything else the same, and you will get the results you expect.