当文本字段具有输入文本时,如何更新约束



我现在有一个问题。我有一个文本字段,一个表视图和一个标签。当文本字段文本为空时,表视图将被隐藏。但是当用户在textField中输入内容时,tableView的列表将显示在View上。TableView 的位置介于 textField 和 label 之间。如何更新此约束?我尝试这样做,但它对我不起作用。谢谢。

class ViewController: UIViewController, UITextFieldDelegate,UITableViewDelegate,UITableViewDataSource {
var tableView: UITableView = UITableView()
var textField: UITextField = UITextField()
var label:UILabel = UILabel()
var haveText:Bool = false
var autoCompletePossibilities = ["Wand","Wizard","Test","1","12","123","1234","12345"]
var autoComplete = [String]()
var tableviewHeightConstraint:NSLayoutConstraint?
override func loadView() {
super.loadView()
tableView.translatesAutoresizingMaskIntoConstraints = false
textField.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
loadContent()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
loadVFL()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
textField.delegate = self
tableView.delegate = self
tableView.dataSource = self
textField.backgroundColor = UIColor.lightGray
tableView.backgroundColor = UIColor.brown
label.backgroundColor = UIColor.cyan
label.text = "hello I'm beginner.Nice."
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func DictionaryOfInstanceVariables(_ container:AnyObject, objects: String ...) -> [String:AnyObject] {
var views = [String:AnyObject]()
for objectName in objects {
guard let object = object_getIvar(container, class_getInstanceVariable(type(of: container), objectName)) else {
assertionFailure("(objectName) is not an ivar of: (container)");
continue
}
views[objectName] = object as AnyObject?
}
return views
}
func loadContent() {
view.addSubview(textField)
view.addSubview(tableView)
view.addSubview(label)
}
func loadVFL() {
let views = DictionaryOfInstanceVariables(self, objects:
"textField"
,"label"
,"tableView"
)
let metrics = ["padding":15]
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[textField]|", options: [], metrics: metrics, views: views))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[label]|", options: [], metrics: metrics, views: views))
self.view.addConstraints (NSLayoutConstraint.constraints(withVisualFormat: "H:|[tableView]|", options: [], metrics: metrics, views: views))
//declare tableview height constraints and init here
tableviewHeightConstraint = NSLayoutConstraint.init(item: view,
attribute: .height,
relatedBy: .equal,
toItem: nil,
attribute: .notAnAttribute,
multiplier: 1,
constant: 0) // init it with a 0 height
tableView.addConstraint(tableviewHeightConstraint!) // add the constraint to the tableView
self.view.addConstraints (NSLayoutConstraint.constraints(withVisualFormat: "V:|-50-[textField(60.0)][tableView][label(30.0)]", options: [], metrics: metrics, views: views))
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let index = indexPath.row as Int
cell.textLabel?.text = autoComplete[index]
cell.backgroundColor = UIColor.green
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autoComplete.count
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
tableviewHeightConstraint?.constant = 160; // required height
UIView.animate(withDuration: 0.5) { // animate so it will be pretty
self.view.layoutIfNeeded()
}
return true
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let subString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
searchAutocompleteEntriesWithSubString(subString: subString)
return true
}
func searchAutocompleteEntriesWithSubString(subString:String)
{
autoComplete.removeAll(keepingCapacity: false)
for key in autoCompletePossibilities {
let myString:NSString = key as NSString
let subStringRange:NSRange = myString.range(of: subString)
if subStringRange.location == 0 {
autoComplete.append(key)
}
}
tableView.reloadData()
}
}

日志打印:

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. 
(
"NSLayoutConstraint:0x60800009be40 V:[UITextField:0x7fc04db09e10]-(0)-[UITableView:0x7fc04e81e400]   (active)",
"NSLayoutConstraint:0x60800009bf30 UITableView:0x7fc04e81e400.height == 150   (active)",
"NSLayoutConstraint:0x60800009d4c0 V:[UITableView:0x7fc04e81e400]-(0)-[UILabel:0x7fc04be057c0'hello I'm beginner.Nice.']   (active)",
"NSLayoutConstraint:0x600000281360 V:[UITextField:0x7fc04db09e10]-(0)-[UILabel:0x7fc04be057c0'hello I'm beginner.Nice.']   (active)"
)
Will attempt to recover by breaking constraint 
NSLayoutConstraint:0x60800009d4c0 V:[UITableView:0x7fc04e81e400]-(0)-[UILabel:0x7fc04be057c0'hello I'm beginner.Nice.']   (active)
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

2017.06.16 更新新的崩溃日志:

崩溃日志在这里。

2017.06.16 终于成功代码:

class ViewController: UIViewController, UITextFieldDelegate,UITableViewDelegate,UITableViewDataSource {
var tableView: UITableView = UITableView()
var textField: UITextField = UITextField()
var label:UILabel = UILabel()
var haveText:Bool = false
var autoCompletePossibilities = ["Wand","Wizard","Test","1","12","123","1234","12345"]
var autoComplete = [String]()
var tableviewHeightConstraint:NSLayoutConstraint?
override func loadView() {
super.loadView()
tableView.translatesAutoresizingMaskIntoConstraints = false
textField.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
loadContent()
loadVFL()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
textField.delegate = self
tableView.delegate = self
tableView.dataSource = self
textField.backgroundColor = UIColor.lightGray
tableView.backgroundColor = UIColor.brown
label.backgroundColor = UIColor.cyan
label.text = "hello I'm beginner.Nice."
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func DictionaryOfInstanceVariables(_ container:AnyObject, objects: String ...) -> [String:AnyObject] {
var views = [String:AnyObject]()
for objectName in objects {
guard let object = object_getIvar(container, class_getInstanceVariable(type(of: container), objectName)) else {
assertionFailure("(objectName) is not an ivar of: (container)");
continue
}
views[objectName] = object as AnyObject?
}
return views
}
func loadContent() {
view.addSubview(textField)
view.addSubview(tableView)
view.addSubview(label)
}
func loadVFL() {
let views = DictionaryOfInstanceVariables(self, objects:
"textField"
,"label"
,"tableView"
)
let metrics = ["padding":15]
tableviewHeightConstraint = NSLayoutConstraint.init(item: tableView,
attribute: .height,
relatedBy: .equal,
toItem: nil,
attribute: .height,
multiplier: 1,
constant: 0) // init it with a 0 height
tableView.addConstraint(tableviewHeightConstraint!) // add the constraint to the tableView
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[textField]|", options: [], metrics: metrics, views: views))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[label]|", options: [], metrics: metrics, views: views))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[tableView]|", options: [], metrics: metrics, views: views))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-50.0-[textField(60.0)][tableView][label(30.0)]", options: [], metrics: metrics, views: views))
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let index = indexPath.row as Int
cell.textLabel?.text = autoComplete[index]
cell.backgroundColor = UIColor.green
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autoComplete.count
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
super.updateViewConstraints()
tableView.removeConstraints(tableView.constraints)
tableviewHeightConstraint = NSLayoutConstraint(item: tableView, attribute: .height, relatedBy: .equal , toItem: nil, attribute: .height, multiplier: 1, constant: 160.0)
tableView.addConstraint(tableviewHeightConstraint!) // add the constraint to the tableView
UIView.animate(withDuration: 0.5) { // animate so it will be pretty
self.updateViewConstraints()
self.view.layoutIfNeeded()
}
return true
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
super.updateViewConstraints()
textField.resignFirstResponder()
tableView.removeConstraints(tableView.constraints)
tableviewHeightConstraint = NSLayoutConstraint(item: tableView, attribute: .height, relatedBy: .equal , toItem: nil, attribute: .height, multiplier: 1, constant: 0.0)
tableView.addConstraint(tableviewHeightConstraint!) // add the constraint to the tableView
UIView.animate(withDuration: 0.5) { // animate so it will be pretty
self.updateViewConstraints()
self.view.layoutIfNeeded()
}
return true
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let subString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
searchAutocompleteEntriesWithSubString(subString: subString)
return true
}
func searchAutocompleteEntriesWithSubString(subString:String)
{
autoComplete.removeAll(keepingCapacity: false)
for key in autoCompletePossibilities {
let myString:NSString = key as NSString
let subStringRange:NSRange = myString.range(of: subString)
if subStringRange.location == 0 {
autoComplete.append(key)
}
}
tableView.reloadData()
}
}

(图片)终于这样看了。

我的方法是加载所有需要的约束loadVFL

func loadVFL() {
let views = DictionaryOfInstanceVariables(self, objects:
"textField"
,"tableView"
,"label"
)
let metrics = ["padding":15]
self.view.addConstraints (NSLayoutConstraint.constraints(withVisualFormat: "H:|[textField]|", options: [], metrics: metrics, views: views))
self.view.addConstraints (NSLayoutConstraint.constraints(withVisualFormat: "H:|[tableView]|", options: [], metrics: metrics, views: views))
self.view.addConstraints (NSLayoutConstraint.constraints(withVisualFormat: "H:|[label]|", options: [], metrics: metrics, views: views))
//declare tableview height constraints and init here
tableviewHeightConstraint = NSLayoutConstraint.init(item: tableView,
attribute: .height,
relatedBy: .equal,
toItem: nil,
attribute: .notAnAttribute,
multiplier: 1,
constant: 0) // init it with a 0 height
tableView.addConstraint(tableviewHeightConstraint) // add the constraint to the tableView
self.view.addConstraints (NSLayoutConstraint.constraints(withVisualFormat: "V:|-50-[textField(60.0)][tableView][label(30.0)]", options: [], metrics: metrics, views: views))
}

textShouldBeginEditing函数中初始化后,激活表视图约束:

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
tableviewHeightConstraint.constant = 160; // required height
UIView.animateWithDuration(0.5) { // animate so it will be pretty
self.view.layoutIfNeeded()
}
return true
}

如果你想在完成搜索时调用的某个函数上隐藏它。只需将常量设置回 0

我认为这应该行得通。试一试,让我知道

最新更新