如何在textField输入文本时更新约束

时间:2017-06-15 01:35:56

标签: ios swift uitableview autolayout constraints

我现在有一个问题。我有一个textField,一个tableView和一个标签。当textField文本为空时,tableView被隐藏。但是当用户在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更新新的崩溃日志:

crash log here.

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()
}
}

(IMAGE) Finally View like this.

1 个答案:

答案 0 :(得分:0)

我的方法是在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函数初始化后,激活您的tableview约束:

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

即可

我认为这应该有效。试一试,让我知道