尽管使用safeAreaLayoutGuide,但在视图中以编程方式创建约束不能解释导航控制器

问题描述

我创建了一个UINavigationController类,该类允许用户注销并显示应用程序的标题。然后,我在其viewControllers数组中添加一个UITabController作为其唯一的viewController:

let homeController = HomeController()

viewControllers = [homeController]

然后在该UITabController(HomeController())中填充一些UIViewControllers-其中一个显示配置文件页面。这是我的第一个项目,我将不会使用情节提要,所以事情一直是很大的挑战!

我在个人资料页面的类和viewDidLoad中创建了UIImageView对象,我使用了:self.view.addSubview(imageView)添加到视图中,然后:imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true,试图将图像锚定到屏幕顶部的UINavigationController栏的底部。但是结果将图像放置在屏幕的最上方,就好像导航栏未被识别为可见。我在这文章中读过:https://medium.com/@amlcurran/a-quick-guide-to-laying-out-views-in-ios-471e92deb74,该'.topLayoutGuide.bottomAnchor'表示导航栏的底部,但现在已折旧到我上面的示例中。 有谁对哪里出什么问题有任何想法吗?还有什么好资源可以让我充分理解以编程方式约束我的元素!谢谢所有人!

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

链接显示了到目前为止的一些代码-我知道其他元素也固定在顶部;我只是想先解决有关导航栏的错误

Image showing what the view displays at the moment

解决方法

您确实应该阅读一些自动布局教程。有很多很多。经过十几遍的学习后,您应该对需要做的事情有个好主意。

同时,这是您对ProfileViewController 进行的编辑,以使您了解自己在做什么错:

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,// 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,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,usernameLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor,// 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
        
    }
    
}

查看代码中的注释以了解我的工作。

结果将如下所示(我在徽标中使用了随机图片)

enter image description here

,

如果要将imageView锚定到safeArea的顶部,则必须像这样将其约束到topAnchor:

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