【问题标题】:How to update constrain when textField have input text当 textField 有输入文本时如何更新约束
【发布时间】:2017-06-15 01:35:55
【问题描述】:

我现在有个问题。我有一个 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.

【问题讨论】:

  • 您在控制台上看到过任何错误吗?
  • 更新我的问题。
  • 哦冲突的约束。我认为你不应该对这个textFieldShouldBeginEditing 施加约束,而是在loadVFL 方法中加载它。改为操纵 UITableView 高度
  • 我明白了。我解决了这个问题。谢谢@Joshua。你真好。

标签: ios swift uitableview autolayout constraints


【解决方案1】:

我的方法是在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

我认为这应该可行。试试看告诉我

【讨论】:

  • 感谢您的回答。是 tableviewHeightConstraint NSLayoutConstraint 吗?我清除“var tableviewHeightConstraint:NSLayoutConstraint?”然后它崩溃了。我更新了有关我的崩溃日志的问题。
  • 那么崩溃日志是什么?
  • 你做了什么?似乎您将高度添加到视图而不是 tableView?
  • 哦,明白了。您只是复制了我的答案而没有检查我传递的项目是否正确。更新。基本上,tableViewheight 约束的项目应该是指 tableView。你能再试一次吗?抱歉@please_tolerate_my_stupid_ques 让我知道它是否有效
  • 感谢您的建议。帮了我很多忙。我把你的概念尝试一下,它成功了。但是我的 textField 顶部约束 V:|-50.0- 看起来像消失了。这很奇怪。
猜你喜欢
  • 2023-03-04
  • 2013-12-17
  • 1970-01-01
  • 2022-11-15
  • 1970-01-01
  • 2022-06-21
  • 2019-10-12
  • 1970-01-01
  • 2020-09-05
相关资源
最近更新 更多