1

I have created a UINavigationController class which allows users to Log out and displays the title of the app. I then added a UITabController as its only viewController in its viewControllers array:

let homeController = HomeController()

viewControllers = [homeController]

This UITabController (HomeController()) is then populated with a few UIViewControllers - one of which will display a Profile page. This is my first project in which I won't be using the storyboard so things have been a great challenge!

I have created a UIImageView object within the class and within my viewDidLoad for my profile page, I have used:self.view.addSubview(imageView)to add to view and then:imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true in an attempt to anchor the image to the bottom of the UINavigationController bar at the top of the screen.However the result places the image at the very top of the screen, as if the Navigation Bar isn't recognised as being visible. I read in this article: https://medium.com/@amlcurran/a-quick-guide-to-laying-out-views-in-ios-471e92deb74, that '.topLayoutGuide.bottomAnchor' represents the bottom of the navigation bar, but this has now been depreciated to my example above. Does anyone have any ideas as to what is wrong?And also any good resources for me to fully understand programmatically constraining my elements!Thanks all!!

https://gist.github.com/JoeMcGeever/a5ce3be94fc49a8f27b1a2867bd9495b

That link shows some of the code so far - I am aware the other elements are also pinned to the top; I am just trying to fix this error regarding the navigation bar first.

Image showing what the view displays at the moment

2 Answers 2

1

You should really go through several auto-layout tutorials. There are many, many of them out there. After you've worked through a dozen or so, you should have a good idea of what needs to be done.

In the meantime, here is your ProfileViewController edited to give you an idea of what you were doing wrong:

class ProfileViewController : UIViewController {
    
    let imageView : UIImageView = { //creates an image view with the name "imageView"
        let image = UIImage(named: "logo")
        let imageView = UIImageView(image: image)
        return imageView
    }()
    
    let usernameLabel = UILabel()
    
    // if you're addint a target referring to "self", this must be a lazy var
    lazy var editProfileButton : UIButton = {
        let editButton = UIButton()
        editButton.backgroundColor = .orange
        editButton.setTitle("Edit Profile", for: .normal)
        editButton.setTitleColor(.white, for: .normal)
        editButton.addTarget(self, action: #selector(handleEdit), for: .touchUpInside)
        return editButton
    }()
    
    @objc func handleEdit(){
        //edit handle button
        print("Edit profile")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.white
        
        self.title = "Profile"
        
        usernameLabel.text = "Username Here"
        
        // we're going to use auto-layout
        [imageView, usernameLabel, editProfileButton].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
        }
        
        self.view.addSubview(imageView)
        self.view.addSubview(usernameLabel)
        self.view.addSubview(editProfileButton)
        
        // need FULL sets of constraints, not just TOP anchors
        
        // respect safe-area
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // image view at upper-left
            // image view 8-pts from top of safe area
            imageView.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0),
            // and 8-pts from left
            imageView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
            // give it a width of, for example, one-quarter the view width
            imageView.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.25),
            // give it a 1:1 ratio (square)
            imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor),
            
            // button at upper-right
            editProfileButton.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0),
            editProfileButton.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
            // no width or height... let the button size itself
            
            // label below the image view
            usernameLabel.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 8.0),
            usernameLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
            // no width or height... let the label size itself

        ])
        
        // give the name label a background color so we can see its frame
        usernameLabel.backgroundColor = .cyan
        
    }
    
}

Review the comments in the code to understand what I did.

Result will look about like this (I used a random image for the logo):

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

Ah I see, thank you so much for your help. Yeah I didn't quite realise how tough it would be changing to programmatically setting my elements. I will start learning now! Thanks again DonMag
0

If you want to anchor your imageView to the top of safeArea, you have to constraint it to the topAnchor like this:

imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true

1 Comment

I have done that: it still looks like what my picture looks like - the view doesn't register the navigation controller when using safeAreaLayoutGuide, it acts as if it isn't present

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.