我正在尝试在一个看起来像下面列出的页面中创建登录名。我编写的代码应在没有徽标和[Login | Register]切换按钮的情况下产生此视图。我的盒子的高度和宽度也不同,但是我并不担心。
目前,我正在获取此输出。我担心单词在顶部如何相互重叠。
在下面列出的代码中,我创建了3个文本字段,按钮和文本字段的容器。我相信函数fieldConstraints中有问题。在此函数中,我浏览了所有文本字段的数组,并为它们分配了必要的约束。除了第一个文本字段之后的每个文本字段的topAnchor设置为等于之前放置在文本字段下方的分隔符的bottomAnchor之外,它们都具有相同的约束。文本字段之间的蓝线是分隔符。
主班
class SignIn: UIViewController {
override func loadView() {
super.loadView()
let inputContainer = inputDataContainer()
constraintsToCenterSubview(forView: inputContainer, width: 100, height: 100)
let nameField = field(for: "Name")
let emailField = field(for: "Email address")
let passField = field(for: "Password")
let fields = [nameField, emailField, passField]
let button = loginButton()
fieldConstraints(subviews: fields, superview: inputContainer)
self.centerViewBelow(forView: button, whichIsBelow: inputContainer, increaseWidthBy: 0)
}
func inputDataContainer() -> UIView{
let inputView = UIView(frame: CGRect(x: self.view.center.x, y: self.view.center.y, width: CGFloat(100), height: CGFloat(100)))
inputView.backgroundColor = UIColor.white
inputView.translatesAutoresizingMaskIntoConstraints = false
inputView.layer.cornerRadius = 5
inputView.layer.masksToBounds = true
self.view.addSubview(inputView)
//inputView = centerViewBelow(forView: inputView, whichIsBelow: self.view, increaseWidthBy: 100)
return inputView
}
func loginButton() -> UIButton {
let button = UIButton()
button.backgroundColor = UIColor(r: 80, g: 101, b: 161)
button.setTitle("Submit", for: [])
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(UIColor.white, for: [])
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
self.view.addSubview(button)
return button
}
func field(for name: String) -> UITextField{
let tf = UITextField()
tf.placeholder = name
tf.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(tf)
return tf
}
func fieldSep() -> UIView {
let view = UIView()
view.backgroundColor = UIColor(r: 220, g: 220, b: 220)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}
func fieldConstraints(subviews: [UIView], superview: UIView) {
var sep: UIView?
let len = subviews.endIndex
for (idx, subview) in subviews.enumerated(){
superview.addSubview(subview)
subview.leftAnchor.constraint(equalTo: superview.leftAnchor)
subview.rightAnchor.constraint(equalTo: superview.rightAnchor)
subview.widthAnchor.constraint(equalTo: superview.widthAnchor)
subview.heightAnchor.constraint(equalTo: superview.heightAnchor, multiplier: CGFloat(1/len))
if (sep != nil){
subview.topAnchor.constraint(equalTo: sep!.bottomAnchor)
}else{
subview.topAnchor.constraint(equalTo: superview.topAnchor)
}
sep = fieldSep()
if idx < subviews.endIndex-1 {
self.view.addSubview(sep!)
sep?.leftAnchor.constraint(equalTo: superview.leftAnchor)
sep?.rightAnchor.constraint(equalTo: superview.rightAnchor)
sep?.topAnchor.constraint(equalTo: subview.bottomAnchor)
}
}
}
}
扩展名
extension UIColor {
convenience init(r:CGFloat, g:CGFloat, b: CGFloat) {
self.init(red: r/255, green: g/255, blue: b/255, alpha: 1)
}
}
extension UIViewController {
func centerViewBelow(forView view: UIView, whichIsBelow topView: UIView, increaseWidthBy constant: CGFloat){
let topConstraint = NSLayoutConstraint(item: view, attribute: .top, relatedBy: .equal, toItem: topView, attribute: .bottom, multiplier: 1, constant: 20)
let widthConstraint = NSLayoutConstraint(item: view, attribute: .width, relatedBy: .equal, toItem: topView, attribute: .width, multiplier: 1, constant: constant)
let centerConstraint = NSLayoutConstraint(item: view, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0)
let heightConstraint = NSLayoutConstraint(item: view, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 50)
NSLayoutConstraint.activate([topConstraint, widthConstraint, centerConstraint, heightConstraint])
//return view
}
func constraintsToCenterSubview(forView view: UIView, width: Int, height: Int){
let centerXConstraint = NSLayoutConstraint(item: view, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0)
let centerYConstraint = NSLayoutConstraint(item: view, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1, constant: 0)
let widthConstraint = NSLayoutConstraint(item: view, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: CGFloat(width))
let heightConstraint = NSLayoutConstraint(item: view, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: CGFloat(height))
NSLayoutConstraint.activate([centerXConstraint, centerYConstraint, widthConstraint, heightConstraint])
}
}
谢谢
更新
因此,通过将容器更改为堆栈视图,我几乎可以做到这一点。但这使我的角落不再圆滑。有人知道如何解决这个问题吗?
func inputDataContainer() -> UIStackView{
let inputView = UIStackView(frame: CGRect(x: self.view.center.x, y: self.view.center.y, width: CGFloat(100), height: CGFloat(100)))
inputView.backgroundColor = UIColor.white
inputView.translatesAutoresizingMaskIntoConstraints = false
inputView.layer.cornerRadius = 5
inputView.layer.masksToBounds = true
inputView.distribution = .fillEqually
inputView.axis = .vertical
inputView.spacing = 1
self.view.addSubview(inputView)
//inputView = centerViewBelow(forView: inputView, whichIsBelow: self.view, increaseWidthBy: 100)
return inputView
}
func fieldConstraints(subviews: [UIView], superview: UIStackView) {
for subview in subviews{
superview.addArrangedSubview(subview)
subview.clipsToBounds = true
}
}
当前应用的屏幕截图示例
答案 0 :(得分:1)
尝试给予高度
sep?.heightAnchor.constraint(equalToConstant:1.0).isActive = true
对于fieldConstraints
中的所有约束,您也会忘记
.isActive = true
或使用NSLayoutConstraint.activate
,例如
NSLayoutConstraint.activate([
subview.leftAnchor.constraint(equalTo: superview.leftAnchor),
subview.rightAnchor.constraint(equalTo: superview.rightAnchor)
subview.widthAnchor.constraint(equalTo: superview.widthAnchor),
subview.heightAnchor.constraint(equalTo: superview.heightAnchor, multiplier: CGFloat(1/len))
])
这种方法行得通,但是最好使用带有分布.fillEqually
的垂直堆栈视图,它将对其进行分区并添加
fileds.forEach { stackview.addArrangedSubview($0) }
答案 1 :(得分:0)
使用UIStackView
。它将帮助您节省构建复杂UI的时间。
答案 2 :(得分:0)
使用UIStackView
会遇到一些麻烦。您可以将其嵌入UIView
中,并为该视图提供圆角,但随后您必须在堆栈视图中的 内的字段中添加填充,以获取分隔线。>
这是另一种可能更适合您的方法。它更接近您的原始代码,将字段和分隔符视图添加到UIView
:
extension UIColor {
convenience init(r:CGFloat, g:CGFloat, b: CGFloat) {
self.init(red: r/255, green: g/255, blue: b/255, alpha: 1)
}
}
class SampleViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(r: 65, g: 92, b: 144)
let nameField = field(for: "Name")
let sep1 = fieldSep()
let emailField = field(for: "Email address")
let sep2 = fieldSep()
let passField = field(for: "Password")
let views = [nameField, sep1, emailField, sep2, passField]
let inputView = inputDataContainer(with: views)
view.addSubview(inputView)
NSLayoutConstraint.activate([
inputView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0),
inputView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20.0),
inputView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0.0),
])
}
func field(for s: String) -> UITextField {
let f = UITextField()
f.translatesAutoresizingMaskIntoConstraints = false
f.placeholder = s
f.borderStyle = .none
return f
}
func fieldSep() -> UIView {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 1.0).isActive = true
v.backgroundColor = UIColor(r: 220, g: 220, b: 220)
return v
}
func inputDataContainer(with subviews: [UIView]) -> UIView {
let horizontalPadding: CGFloat = 8.0
let verticalSpacing: CGFloat = 8.0
let containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.backgroundColor = .white
containerView.layer.cornerRadius = 5
var previousView: UIView?
for subview in subviews{
containerView.addSubview(subview)
// if it's a text field, we want padding on left and right
if subview is UITextField {
subview.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: horizontalPadding).isActive = true
subview.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -horizontalPadding).isActive = true
} else {
subview.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 0.0).isActive = true
subview.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: 0.0).isActive = true
}
if subview == subviews.first {
// if it's the first subview, constrain to top of container
subview.topAnchor.constraint(equalTo: containerView.topAnchor, constant: verticalSpacing).isActive = true
} else {
// unwrap previousView and constrain subview to bottom of previous subview
if let pv = previousView {
subview.topAnchor.constraint(equalTo: pv.bottomAnchor, constant: verticalSpacing).isActive = true
}
}
if subview == subviews.last {
// if it's the last subview, constrain to bottom of container
subview.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -verticalSpacing).isActive = true
}
// save reference to current subview
previousView = subview
}
return containerView
}
}
结果: