Jax
Jax

Reputation: 210

UINavigationController pushing entire UIView to top left

I am working through 100 Days of Swift without the use of Storyboards and am running into some issues with the UI View almost fully being pushed under the UINavigationController. When removing the UINavigationController everything works as expected. I've attempted to add a new view, set edgesForExtendedLayout =[], and adjusting the y of my CGRect to no avail. I am almost certain I am doing something quite goofy, but cannot for the life of me figure out what.

Screenshot of what the view looks like: enter image description here

Expected is for the 3 buttons to be displayed starting under the navView.

SceneDelegate.swift:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
      guard let windowScene = (scene as? UIWindowScene) else { return }
      window = UIWindow(frame: windowScene.coordinateSpace.bounds)
      let viewController = ViewController()
      window?.rootViewController = UINavigationController(rootViewController: viewController)
      window?.makeKeyAndVisible()
      window?.windowScene = windowScene
    }

ViewController.swift:

class ViewController: UIViewController {

    var button1: UIButton!
    var button2: UIButton!
    var button3: UIButton!
        
    var countries = [String]()
    var score = 0
    var correctAnswer = 0
            
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white

        button1 = UIButton(type: .custom)
        button1.setImage(UIImage(named: "us"), for: .normal)
        button1.translatesAutoresizingMaskIntoConstraints = false
        button1.frame = CGRect(x: 100, y: 100, width: 200, height: 100)
        button1.layer.borderWidth = 1
        button1.layer.borderColor = UIColor.lightGray.cgColor
        view.addSubview(button1)
        
        button2 = UIButton(type: .custom)
        button2.setImage(UIImage(named: "us"), for: .normal)
        button2.translatesAutoresizingMaskIntoConstraints = false
        button2.frame = CGRect(x: 100, y: 230, width: 200, height: 100)
        button2.layer.borderWidth = 1
        button2.layer.borderColor = UIColor.lightGray.cgColor
        view.addSubview(button2)
        
        button3 = UIButton(type: .custom)
        button3.setImage(UIImage(named: "us"), for: .normal)
        button3.translatesAutoresizingMaskIntoConstraints = false
        button3.frame = CGRect(x: 100, y: 360, width: 200, height: 100)
        button3.layer.borderWidth = 1
        button3.layer.borderColor = UIColor.lightGray.cgColor
        view.addSubview(button3)
        
        countries += ["estonia", "france", "germany", "ireland", "italy", "monaco", "nigeria", "poland", "russia", "spain", "uk", "us"]
        
        
        askQuestion()
    }
    
    func askQuestion() {
        countries.shuffle()
        correctAnswer = Int.random(in: 0...2)
        
        button1.setImage(UIImage(named: countries[0]), for: .normal)
        button2.setImage(UIImage(named: countries[1]), for: .normal)
        button3.setImage(UIImage(named: countries[2]), for: .normal)
        
        title = countries[correctAnswer].uppercased()
    }
}

Upvotes: 0

Views: 49

Answers (2)

DonMag
DonMag

Reputation: 77462

As per the OP's comments...

The issue is that for each button you are setting:

button1.translatesAutoresizingMaskIntoConstraints = false

but then are trying to explicitly set the button frames:

button1.frame = CGRect(x: 100, y: 100, width: 200, height: 100)

You want to either use auto-layout or explicit frames. Mixing them will lead to trouble, with the UI elements not showing up where you expect them (as you have seen).

Upvotes: 1

ZG324
ZG324

Reputation: 66

Since you are building the view without using Storyboard. You should add constraints to place the buttons programmatically.

Add the code bellow to viewDidLoad func

button1.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.init(item: button1!, attribute: .top, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .top, multiplier: 1, constant: 0).isActive = true

Or,

button1.translatesAutoresizingMaskIntoConstraints = false
button1.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true

They do the same thing - programmatically adding a constraint from button1 to top safeArea. You can also add constraints to button2 and button3 as you wish.

Upvotes: 0

Related Questions