Why is my StackView not working? Elements are completely displaced

让人想犯罪 __ 提交于 2020-12-08 05:09:40

问题


Hey my StackView is doing nothing, there are two problems: The first is that the elements on the VC are completely displaced when I turn around the simulator or change the device, so the StackView is not doing what it should do! The second thing is that the StackView is covering the navigation bar and I don't know how to make it visible. Can someone help me?

import UIKit


class RegisterViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    let stackView = UIStackView()
    
    
    var profilePicture = UIButton()
    var profileIcon = UIImage()
    let usernameTextField = UITextField()
    let emailTextField = UITextField()
    let passswordTextField = UITextField()
    let signInButton = UIButton()
    
    
   
    

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationController?.navigationBar.prefersLargeTitles = true
        navigationItem.title = "Create an Account"
        view.backgroundColor = .white
        
        
        
        
        
        // SetUp StackView:
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.alignment = .center
        stackView.distribution = .fillEqually
        stackView.spacing = 50
        view.addSubview(stackView)
       
        
        // SetUp Stack View Constraints:
       
        stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20).isActive = true
        stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
               
        
        //Add Elements
        
        stackView.addArrangedSubview(profilePicture)
        stackView.addArrangedSubview(usernameTextField)
        stackView.addArrangedSubview(passswordTextField)
        stackView.addArrangedSubview(signInButton)
        
        
    
    
// MARK: - Set-Up View-Elements
    
    
    // SetUp ProfileIcon:
        profileIcon = UIImage(named: "characteer")!
        profilePicture.setImage(profileIcon, for: .normal)
        profilePicture.imageView?.contentMode = .scaleAspectFill
        let cornerRadius: CGFloat
         cornerRadius = 75 // half of widht/height
        profilePicture.layer.cornerRadius = cornerRadius
        profilePicture.layer.masksToBounds = true
        profilePicture.layer.borderWidth = 1
        profilePicture.layer.borderColor = UIColor.white.cgColor
        profilePicture.addTarget(self, action: #selector(handleSelectedPhoto), for: .touchUpInside)
        
        
        view.addSubview(profilePicture)
        
       profilePicture.translatesAutoresizingMaskIntoConstraints = false
       profilePicture.heightAnchor.constraint(equalToConstant: 150).isActive = true
       profilePicture.widthAnchor.constraint(equalToConstant: 150).isActive = true
       profilePicture.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        profilePicture.topAnchor.constraint(equalTo: view.topAnchor, constant: 110).isActive = true
        
     
        
        // SetUp UsernameTextfield:
    usernameTextField.backgroundColor = .white
    usernameTextField.attributedPlaceholder = NSAttributedString(string: "Username", attributes: [NSAttributedString.Key.foregroundColor: UIColor.lightGray])
    usernameTextField.textAlignment = NSTextAlignment.center
    usernameTextField.layer.cornerRadius = 8
    usernameTextField.layer.borderWidth = 1
    usernameTextField.layer.borderColor = UIColor.lightGray.cgColor
    self.view.addSubview(usernameTextField)
    let username = usernameTextField.text
    
    usernameTextField.translatesAutoresizingMaskIntoConstraints = false
    
    usernameTextField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
    usernameTextField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
    usernameTextField.heightAnchor.constraint(equalToConstant: 50).isActive = true
    usernameTextField.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    
        
    
// SetUpEmailTextfield:
    emailTextField.backgroundColor = .white
           emailTextField.attributedPlaceholder = NSAttributedString(string: "Email", attributes: [NSAttributedString.Key.foregroundColor: UIColor.lightGray])
           emailTextField.textAlignment = NSTextAlignment.center
           emailTextField.layer.cornerRadius = 8
           emailTextField.layer.borderWidth = 1
           emailTextField.layer.borderColor = UIColor.lightGray.cgColor
           self.view.addSubview(emailTextField)
           
           emailTextField.translatesAutoresizingMaskIntoConstraints = false
           emailTextField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
           emailTextField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
           emailTextField.heightAnchor.constraint(equalToConstant: 50).isActive = true
           emailTextField.topAnchor.constraint(equalTo: usernameTextField.bottomAnchor, constant: 20).isActive = true
        
        ```

回答1:


You're doing a number of things wrong... It would be well worth your while to go through a few tutorials on auto-layout and using UIStackView.

First, if you add a view (image view, text field, label, button, etc) to a stack view, do not also give those views position constraints. That's what the stack view is doing.

Second, once you've added a view:

stackView.addArrangedSubview(profilePicture)

do not then add it as a subview like this:

view.addSubview(profilePicture)

Doing that will remove profilePicture from the stack view.

Take a look through your code -- review the comments where I've made changes:

class RegisterViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    let stackView = UIStackView()
    
    var profilePicture = UIButton()
    var profileIcon = UIImage()
    let usernameTextField = UITextField()
    let emailTextField = UITextField()
    let passswordTextField = UITextField()
    let signInButton = UIButton()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationController?.navigationBar.prefersLargeTitles = true
        navigationItem.title = "Create an Account"
        view.backgroundColor = .white
        
        
        // SetUp StackView:
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.alignment = .center
        
        // distribution should be .fill  NOT  .fillEqually
        stackView.distribution = .fill
        
        stackView.spacing = 50
        view.addSubview(stackView)
        
        // SetUp Stack View Constraints:
        
        stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20).isActive = true
        stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        
        //Add Elements
        
        stackView.addArrangedSubview(profilePicture)
        stackView.addArrangedSubview(usernameTextField)
        stackView.addArrangedSubview(emailTextField)
        stackView.addArrangedSubview(passswordTextField)
        stackView.addArrangedSubview(signInButton)
        
        // MARK: - Set-Up View-Elements
        
        // SetUp ProfileIcon:
        //profileIcon = UIImage(named: "characteer")!
        profileIcon = UIImage(named: "pro1")!
        profilePicture.setImage(profileIcon, for: .normal)
        profilePicture.imageView?.contentMode = .scaleAspectFill
        let cornerRadius: CGFloat
        cornerRadius = 75 // half of widht/height
        profilePicture.layer.cornerRadius = cornerRadius
        profilePicture.layer.masksToBounds = true
        profilePicture.layer.borderWidth = 1
        profilePicture.layer.borderColor = UIColor.white.cgColor
        //profilePicture.addTarget(self, action: #selector(handleSelectedPhoto), for: .touchUpInside)
        
        // NO - it's already in the stack view
        //view.addSubview(profilePicture)
        
        // Set Only Width and Height - position is managed by the stack view
        profilePicture.heightAnchor.constraint(equalToConstant: 150).isActive = true
        profilePicture.widthAnchor.constraint(equalToConstant: 150).isActive = true
        
        // SetUp UsernameTextfield:
        usernameTextField.backgroundColor = .white
        usernameTextField.attributedPlaceholder = NSAttributedString(string: "Username", attributes: [NSAttributedString.Key.foregroundColor: UIColor.lightGray])
        usernameTextField.textAlignment = NSTextAlignment.center
        usernameTextField.layer.cornerRadius = 8
        usernameTextField.layer.borderWidth = 1
        usernameTextField.layer.borderColor = UIColor.lightGray.cgColor

        // NO - it's already in the stack view
        //  self.view.addSubview(usernameTextField)
        let username = usernameTextField.text
        
        // Set Only Width and Height - position is managed by the stack view
        usernameTextField.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -40).isActive = true
        usernameTextField.heightAnchor.constraint(equalToConstant: 50).isActive = true
        
        // SetUpEmailTextfield:
        emailTextField.backgroundColor = .white
        emailTextField.attributedPlaceholder = NSAttributedString(string: "Email", attributes: [NSAttributedString.Key.foregroundColor: UIColor.lightGray])
        emailTextField.textAlignment = NSTextAlignment.center
        emailTextField.layer.cornerRadius = 8
        emailTextField.layer.borderWidth = 1
        emailTextField.layer.borderColor = UIColor.lightGray.cgColor

        // NO - it's already in the stack view
        //  self.view.addSubview(emailTextField)
        
        // Set Only Width and Height - position is managed by the stack view
        emailTextField.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -40).isActive = true
        emailTextField.heightAnchor.constraint(equalToConstant: 50).isActive = true
        
        // SetUp PasswordTextfield:
        passswordTextField.backgroundColor = .white
        passswordTextField.attributedPlaceholder = NSAttributedString(string: "Password", attributes: [NSAttributedString.Key.foregroundColor: UIColor.lightGray])
        passswordTextField.textAlignment = NSTextAlignment.center
        passswordTextField.layer.cornerRadius = 8
        passswordTextField.layer.borderWidth = 1
        passswordTextField.layer.borderColor = UIColor.lightGray.cgColor

        // NO - it's already in the stack view
        //  self.view.addSubview(emailTextField)
        
        // Set Only Width and Height - position is managed by the stack view
        passswordTextField.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -40).isActive = true
        passswordTextField.heightAnchor.constraint(equalToConstant: 50).isActive = true
        
        signInButton.setTitle("Sign In", for: [])
        signInButton.backgroundColor = .blue

        // Set Only Width and Height - position is managed by the stack view
        signInButton.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -40).isActive = true
        signInButton.heightAnchor.constraint(equalToConstant: 50).isActive = true

    }

}

Of course, using that layout - where you specified vertical spacing between the elements of 50-pts, and you've set explicit heights for each element, you'll likely find that it doesn't "fit quite right" across different devices / screen sizes.

So, as pointed out to you in your previous question here: Why is my VC displaced after changing the Simulator? AutoLayout - you probably want to change the stack view's Distribution to Equal Spacing and add a bottom constraint:

    stackView.distribution = .equalSpacing
    stackView.spacing = 0

    stackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20).isActive = true

That may or may not give you exactly what you want, but it's a starting point.




回答2:


Just I set for profilePicture and usernameTextField but for others are same it works. Wrong side of your code is about constraint and you add object two different views. There is a solution.

    let stackView = UIStackView()
    
    
    var profilePicture = UIButton()
    var profileIcon = UIImage()
    let usernameTextField = UITextField()
    let emailTextField = UITextField()
    let passswordTextField = UITextField()
    let signInButton = UIButton()
    
    
   
    

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationController?.navigationBar.prefersLargeTitles = true
        navigationItem.title = "Create an Account"
        view.backgroundColor = .white
        
        
        
        
        
        // SetUp StackView:
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.alignment = .center
        stackView.distribution = .fillEqually
        stackView.spacing = 50
        view.addSubview(stackView)
       
        
        // SetUp Stack View Constraints:
       
        stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20).isActive = true
        stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
        stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
               
        
        //Add Elements
        
        stackView.addArrangedSubview(profilePicture)
        stackView.addArrangedSubview(usernameTextField)
        
        
    
    
// MARK: - Set-Up View-Elements
    
    
    // SetUp ProfileIcon:
       profileIcon = UIImage(named: "characteer")!
        profilePicture.setImage(profileIcon, for: .normal)
        profilePicture.imageView?.contentMode = .scaleAspectFill
        let cornerRadius: CGFloat
         cornerRadius = 75 // half of widht/height
        profilePicture.layer.cornerRadius = cornerRadius
        profilePicture.layer.masksToBounds = true
        profilePicture.layer.borderWidth = 1
        profilePicture.layer.borderColor = UIColor.white.cgColor
        //profilePicture.addTarget(self, action: #selector(handleSelectedPhoto), for: .touchUpInside)
        
        
       profilePicture.translatesAutoresizingMaskIntoConstraints = false
       profilePicture.heightAnchor.constraint(equalToConstant: 150).isActive = true
       profilePicture.widthAnchor.constraint(equalToConstant: 150).isActive = true
        
     
        
        // SetUp UsernameTextfield:
    usernameTextField.backgroundColor = .white
    usernameTextField.attributedPlaceholder = NSAttributedString(string: "Username", attributes: [NSAttributedString.Key.foregroundColor: UIColor.lightGray])
    usernameTextField.textAlignment = NSTextAlignment.center
    usernameTextField.layer.cornerRadius = 8
    usernameTextField.layer.borderWidth = 1
    usernameTextField.layer.borderColor = UIColor.lightGray.cgColor
    let username = usernameTextField.text
    
    usernameTextField.translatesAutoresizingMaskIntoConstraints = false
        usernameTextField.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width-40).isActive = true
    usernameTextField.heightAnchor.constraint(equalToConstant: 50).isActive = true



回答3:


I think there is a problem about your constraint.

profilePicture.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true profilePicture.topAnchor.constraint(equalTo: view.topAnchor, constant: 110).isActive = true

are trying to center of the screen but they are inside of stack view. Also you have to give a static height to stack view on this scenario.



来源:https://stackoverflow.com/questions/64552077/why-is-my-stackview-not-working-elements-are-completely-displaced

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!