如何在不破坏约束的情况下以编程方式将 UITextField 添加到 UIScrollView?
How to add UITextField programmatically to UIScrollView without breaking constraints?
情况是这样的:我有一个嵌入 UIScrollView 的表单,在表单中有一个部分,用户可以在其中添加 N 个文本字段,所以如果一开始我有这个:
UITextField - textField1
UIButton - Add
当按下 Add
时,我想要这个:
UITextField - textField1
UITextField - textField2
UIButton - Add
虽然添加了文本字段,但无法满足约束条件,因此 UI 中断
那个日志:
[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<_UILayoutSupportConstraint:0x1c4c800a0 _UILayoutGuide:0x106ccf4e0.height == 64 (active)>",
"<_UILayoutSupportConstraint:0x1c4c80050 V:|-(0)-[_UILayoutGuide:0x106ccf4e0] (active, names: '|':UIView:0x106ccdc10 )>",
"<_UILayoutSupportConstraint:0x1c4c80ff0 _UILayoutGuide:0x106ccf6d0.height == 0 (active)>",
"<_UILayoutSupportConstraint:0x1c4c801e0 _UILayoutGuide:0x106ccf6d0.bottom == UIView:0x106ccdc10.bottom (active)>",
"<NSLayoutConstraint:0x1c4c80550 UIImageView:0x106cce6c0.height == 5 (active)>",
"<NSLayoutConstraint:0x1c4c80640 UILabel:0x106ccf070'Completa tu Perfil'.height == 24 (active)>",
"<NSLayoutConstraint:0x1c0c886b0 form-view.height == 579 (active, names: form-view:0x10ed307c0 )>",
"<NSLayoutConstraint:0x1c0c8a1e0 V:|-(0)-[form-view] (active, names: form-view:0x10ed307c0, '|':UIScrollView:0x107a37000 )>",
"<NSLayoutConstraint:0x1c0c8a320 V:[form-view]-(0)-[profiles-view] (active, names: profiles-view:0x106ccd430, form-view:0x10ed307c0 )>",
"<NSLayoutConstraint:0x1c4c80af0 V:[_UILayoutGuide:0x106ccf4e0]-(10)-[UILabel:0x106ccf070'Completa tu Perfil'] (active)>",
"<NSLayoutConstraint:0x1c4c80cd0 V:[UILabel:0x106ccf070'Completa tu Perfil']-(8)-[UIImageView:0x106cce6c0] (active)>",
"<NSLayoutConstraint:0x1c4c80d20 V:[UIImageView:0x106cce6c0]-(0)-[UIScrollView:0x107a37000] (active)>",
"<NSLayoutConstraint:0x1c4c80e10 UIImageView:0x106ccddf0.top == profiles-view.top (active, names: profiles-view:0x106ccd430 )>",
"<NSLayoutConstraint:0x1c4c80f00 V:[UIImageView:0x106ccddf0]-(0)-[_UILayoutGuide:0x106ccf6d0] (active)>",
"<NSLayoutConstraint:0x1c0c8bdb0 'UIView-Encapsulated-Layout-Height' UIView:0x106ccdc10.height == 667 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x1c0c886b0 form-view.height == 579 (active, names: form-view:0x10ed307c0 )>
因此,由于高度限制被打破,AutoLayout 会按照允许视图以这种方式打破的边距限制排列元素。
也就是说,我添加约束的方式是这样的:
func addModelButtonAction(_ sender: Any) { // an IBAction
addButton.isHighlighted = false
let last = modelTextFields.last!
let textField = last.createCopy() // extension method for creating a copy of the last textField
modelTextFieldsView.insertSubview(textField, belowSubview: last)
let growth = last.frame.height + 8 // the 8 represents the top spacing between textFields
formViewHeight.constant += growth // increasing height of the view where the form is embeded
modelTextFieldsHeight.constant += growth // increasing height of the view where the textFields are embeded
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
textField.frame.origin.y += growth // moving new textField below the previous one
}
modelTextFields.append(textField) // array of UITextField to keep track of the textFields in screen
}
以及视图的对齐矩形:
以及视图的层次结构:
我该怎么做才能使这项工作按预期进行?感谢您在这方面的帮助,因为我一直试图解决这个问题,但没有成功。
提前致谢!
您有几个选项可以解决此布局问题:
就个人而言,我可能会尝试将这些视图嵌入 UIStackView
。堆栈视图将为您管理垂直布局,允许您根据需要插入和删除子视图。 UIStackView
如果您使用情节提要,则在 Interface Builder 中使用起来特别容易。
或者,您可以为此布局使用 UITableView
;它会代表你管理垂直流,从你身上抽象出很多令人头疼的布局问题,尽管你需要自己管理数据源和单元格。
通过仔细管理不同约束的优先级,允许在布局更改时破坏某些约束,您可以在没有这些条件的情况下使此布局正常工作,但这可能是一件乏味的工作。
情况是这样的:我有一个嵌入 UIScrollView 的表单,在表单中有一个部分,用户可以在其中添加 N 个文本字段,所以如果一开始我有这个:
UITextField - textField1
UIButton - Add
当按下 Add
时,我想要这个:
UITextField - textField1
UITextField - textField2
UIButton - Add
虽然添加了文本字段,但无法满足约束条件,因此 UI 中断
那个日志:
[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<_UILayoutSupportConstraint:0x1c4c800a0 _UILayoutGuide:0x106ccf4e0.height == 64 (active)>",
"<_UILayoutSupportConstraint:0x1c4c80050 V:|-(0)-[_UILayoutGuide:0x106ccf4e0] (active, names: '|':UIView:0x106ccdc10 )>",
"<_UILayoutSupportConstraint:0x1c4c80ff0 _UILayoutGuide:0x106ccf6d0.height == 0 (active)>",
"<_UILayoutSupportConstraint:0x1c4c801e0 _UILayoutGuide:0x106ccf6d0.bottom == UIView:0x106ccdc10.bottom (active)>",
"<NSLayoutConstraint:0x1c4c80550 UIImageView:0x106cce6c0.height == 5 (active)>",
"<NSLayoutConstraint:0x1c4c80640 UILabel:0x106ccf070'Completa tu Perfil'.height == 24 (active)>",
"<NSLayoutConstraint:0x1c0c886b0 form-view.height == 579 (active, names: form-view:0x10ed307c0 )>",
"<NSLayoutConstraint:0x1c0c8a1e0 V:|-(0)-[form-view] (active, names: form-view:0x10ed307c0, '|':UIScrollView:0x107a37000 )>",
"<NSLayoutConstraint:0x1c0c8a320 V:[form-view]-(0)-[profiles-view] (active, names: profiles-view:0x106ccd430, form-view:0x10ed307c0 )>",
"<NSLayoutConstraint:0x1c4c80af0 V:[_UILayoutGuide:0x106ccf4e0]-(10)-[UILabel:0x106ccf070'Completa tu Perfil'] (active)>",
"<NSLayoutConstraint:0x1c4c80cd0 V:[UILabel:0x106ccf070'Completa tu Perfil']-(8)-[UIImageView:0x106cce6c0] (active)>",
"<NSLayoutConstraint:0x1c4c80d20 V:[UIImageView:0x106cce6c0]-(0)-[UIScrollView:0x107a37000] (active)>",
"<NSLayoutConstraint:0x1c4c80e10 UIImageView:0x106ccddf0.top == profiles-view.top (active, names: profiles-view:0x106ccd430 )>",
"<NSLayoutConstraint:0x1c4c80f00 V:[UIImageView:0x106ccddf0]-(0)-[_UILayoutGuide:0x106ccf6d0] (active)>",
"<NSLayoutConstraint:0x1c0c8bdb0 'UIView-Encapsulated-Layout-Height' UIView:0x106ccdc10.height == 667 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x1c0c886b0 form-view.height == 579 (active, names: form-view:0x10ed307c0 )>
因此,由于高度限制被打破,AutoLayout 会按照允许视图以这种方式打破的边距限制排列元素。
也就是说,我添加约束的方式是这样的:
func addModelButtonAction(_ sender: Any) { // an IBAction
addButton.isHighlighted = false
let last = modelTextFields.last!
let textField = last.createCopy() // extension method for creating a copy of the last textField
modelTextFieldsView.insertSubview(textField, belowSubview: last)
let growth = last.frame.height + 8 // the 8 represents the top spacing between textFields
formViewHeight.constant += growth // increasing height of the view where the form is embeded
modelTextFieldsHeight.constant += growth // increasing height of the view where the textFields are embeded
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
textField.frame.origin.y += growth // moving new textField below the previous one
}
modelTextFields.append(textField) // array of UITextField to keep track of the textFields in screen
}
以及视图的对齐矩形:
以及视图的层次结构:
我该怎么做才能使这项工作按预期进行?感谢您在这方面的帮助,因为我一直试图解决这个问题,但没有成功。
提前致谢!
您有几个选项可以解决此布局问题:
就个人而言,我可能会尝试将这些视图嵌入 UIStackView
。堆栈视图将为您管理垂直布局,允许您根据需要插入和删除子视图。 UIStackView
如果您使用情节提要,则在 Interface Builder 中使用起来特别容易。
或者,您可以为此布局使用 UITableView
;它会代表你管理垂直流,从你身上抽象出很多令人头疼的布局问题,尽管你需要自己管理数据源和单元格。
通过仔细管理不同约束的优先级,允许在布局更改时破坏某些约束,您可以在没有这些条件的情况下使此布局正常工作,但这可能是一件乏味的工作。