如何向动态创建的UITextField添加约束?

时间:2017-01-06 13:32:46

标签: swift

我已动态创建了UITextFields。现在我想引用TextFields来检查一些约束。我该怎么做?

func displayTextBox1(height: Int, placeHolder: String, xtb: Int, ytb: Int, lableName: String, xl: Int, yl: Int) {
    DispatchQueue.main.async{
        self.textField = UITextField(frame: CGRect(x: xtb, y: ytb, width: 343, height: height))
        self.textField.textAlignment = NSTextAlignment.left
        self.textField.textColor = UIColor.black
        self.textField.borderStyle = UITextBorderStyle.line
        self.textField.autocapitalizationType = UITextAutocapitalizationType.words // If you need any capitalization
        self.textField.placeholder = placeHolder

        print("hi")

        self.view.addSubview(self.textField)
        self.displayLabel(labelName: lableName, x: xl, y: yl)
    }
}

2 个答案:

答案 0 :(得分:1)

您可以使用下面的示例解释代码设置编程约束:

let constraint = NSLayoutConstraint(item: self.textField, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.width, multiplier: 1, constant: -50)
NSLayoutConstraint.activate([constraint])

正如您所看到的,我正在为项目textField创建一个约束,其宽度应等于视图的宽度乘以1减去50.这意味着textField的宽度将比视图的宽度小50个像素。最后一行代码激活给定的一组创建约束。

答案 1 :(得分:1)

欢迎来到Stackoverflow,希望您喜欢学习Swift!

我将根据您的代码段做出一些假设:

  • 创建文本字段和标签(位置,占位符文本等)所需的详细信息来自某个在后台线程上运行的服务(可能是HTTP请求?),这就是您使用DispatchQueue.main.async的原因在主线程上执行UI事件。
  • 将会有多个文本字段/标签对,您将要配置并添加到界面(不只是一对)...也许是'todo'列表应用程序的位置标签和文本字段让人们输入一个注释(在答案的第2部分中更多内容),这就是为什么这些视图(和约束)是在代码而不是在故事板中创建的。
  • 您希望投资基于约束的布局,而不是基于帧的定位。

回答第1部分

如果这些假设中的任何一个是不正确的,那么这个答案的部分内容可能就不相关了。

但假设假设是正确的,我建议做几件事:

  • 使用单独的辅助方法创建文本字段/视图并返回结果(而不是在单个方法中执行所有操作) - 具有单一用途的方法将更有意义并且更容易遵循。< / p>

  • 不要使用设置视图位置/大小与框架和约束的混合 - 使用一种方法或另一种方法(因为你是新的,它将更容易保持一个心理模型的事情是如何工作的而不是混合)。

以下是视图控制器类可能开始的样子片段:

import UIKit

class ViewController: UIViewController {

    func triggeredBySomeEvent() {

        // assuming that you have some equivilent to `YouBackgroundRequestManager.getTextFieldLabelDetails`
        // that grabs the info you need to create the label and textfield on a background thread...
        YouBackgroundRequestManager.getTextFieldLabelDetails { tfPlaceholder, tfHeight, tfX, tfY, labelName, labelX, labelY in

            // perform UI work on the main thread
            DispatchQueue.main.async{

                // use our method to dynamically create a textfield
                let newTextField: UITextField = self.createTextfield(with: tfPlaceholder, height: tfHeight)

                // add textfield to a container view (in this case the view controller's view)
                self.view.addSubview(newTextField)

                // add constraints that pin the textfield's left and top anchor relative to the left and top anchor of the view
                newTextField.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: tfX).isActive = true
                newTextField.topAnchor.constraint(equalTo: self.view.topAnchor, constant: tfY).isActive = true

                // repeat for label...
                let newLabel: UILabel = self.createLabel(with: labelName)
                self.view.addSubview(newLabel)
                newLabel.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: labelX).isActive = true
                newLabel.topAnchor.constraint(equalTo: self.view.topAnchor, constant: labelY).isActive = true
            }
        }
    }

    // create, configure, and return a new textfield
    func createTextfield(with placeholder: String, height: CGFloat) -> UITextField {

        let textField = UITextField(frame: .zero) // set the frame to zero because we're going to manage this with constraints
        textField.placeholder = placeholder
        textField.textAlignment = .left
        textField.textColor = .black
        textField.borderStyle = .line
        textField.autocapitalizationType = .words

        // translatesAutoresizingMaskIntoConstraints = false is important here, if you don't set this as false,
        // UIKit will automatically create constraints based on the `frame` of the view.
        textField.translatesAutoresizingMaskIntoConstraints = false
        textField.heightAnchor.constraint(equalToConstant: height).isActive = true
        textField.widthAnchor.constraint(equalToConstant: 343.0).isActive = true

        return textField
    }

    // create, configure and return a new label
    func createLabel(with labelName: String) -> UILabel {
        let label = UILabel()
        label.text = labelName
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }
}

回答第2部分

我很难想象你真正想要这样做的情况。如果您正在创建一个元素重复的UI(如todo列表,或者可能是电子表格类型的界面),那么这种方法不是正确的方法。

如果您想创建一个UI,其中元素重复自己作为单个列中的重复元素,您应该使用UITableViewController进行调查,在其中创建表示单个元素的单元格,并使用tableview管理该集合细胞

如果您想创建一个UI,其中元素以垂直列表之外的任何其他方式重复,那么您使用UICollectionViewController进行调查,这更复杂,但功能更强大。

道歉,如果这个答案偏离主题,但希望激发一些对你有用的想法。