为啥我的 StackView 不工作?元素完全移位
Posted
技术标签:
【中文标题】为啥我的 StackView 不工作?元素完全移位【英文标题】:Why is my StackView not working? Elements are completely displaced为什么我的 StackView 不工作?元素完全移位 【发布时间】:2020-10-27 10:03:55 【问题描述】:嘿,我的 StackView 什么也没做,有两个问题: 第一个是我转模拟器或者换设备的时候VC上的元素完全移位了,所以StackView没有做它应该做的! 第二件事是 StackView 覆盖了导航栏,我不知道如何使其可见。 有人可以帮我吗?
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】:我只是为 profilePicture 和 usernameTextField 设置,但对于其他人来说是一样的。您的代码的错误方面是关于约束,并且您添加了两个不同的视图对象。有解决办法。
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
【讨论】:
【参考方案2】:您做错了很多事情...阅读一些有关自动布局和使用 UIStackView
的教程非常值得。
首先,如果您将视图(图像视图、文本字段、标签、按钮等)添加到堆栈视图,不要也给这些视图位置约束.这就是堆栈视图正在做的事情。
其次,添加视图后:
stackView.addArrangedSubview(profilePicture)
不要然后像这样将其添加为子视图:
view.addSubview(profilePicture)
这样做将从堆栈视图中删除 profilePicture
。
查看您的代码——查看我进行更改的 cmets:
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
当然,使用该布局 - 您在元素之间指定了 50 磅的垂直间距,并且为每个元素设置了明确的高度,您可能会发现它并不“完全适合”不同的设备/屏幕尺寸。
因此,正如您在上一个问题中向您指出的那样:Why is my VC displaced after changing the Simulator? AutoLayout - 您可能希望将堆栈视图的分布更改为等间距并添加底部约束:
stackView.distribution = .equalSpacing
stackView.spacing = 0
stackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20).isActive = true
这可能会或可能不会完全满足您的需求,但这是一个起点。
【讨论】:
【参考方案3】:我认为你的约束有问题。
profilePicture.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true profilePicture.topAnchor.constraint(equalTo: view.topAnchor, constant: 110).isActive = true
试图在屏幕的中心,但它们在堆栈视图内。在这种情况下,您还必须为堆栈视图提供静态高度。
【讨论】:
以上是关于为啥我的 StackView 不工作?元素完全移位的主要内容,如果未能解决你的问题,请参考以下文章
如何禁用 BottomNavigationView 移位模式?