更改对象的框架大小后更新自动布局

Updating auto layout after changing an object's frame size

我正在使用自动布局创建视图,结果是这样的。

加载视图后,我会获取一些文本数据并填充 UITextView。 "About me" 项目可以是多行,因此我调整了该特定框架的大小。然后,我得到以下信息。

你看到关于我的文本视图是如何覆盖下一个字段的吗?如何使用新的关于我的文本视图大小调整自动布局的大小?我搜索并找到了一些使用 setNeedsLayout 和 layoutIfNeeded 的建议,但 none 有效。

我正在设置自动布局,如下所示:

    inputsContainerView.addSubview(ageInput)
    ageInput.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor).isActive = true
    ageInput.topAnchor.constraint(equalTo: inputsContainerView.topAnchor, constant: 10).isActive = true
    ageInput.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
    ageInput.heightAnchor.constraint(equalToConstant: 60).isActive = true

    inputsContainerView.addSubview(genderInput)
    genderInput.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor).isActive = true
    genderInput.topAnchor.constraint(equalTo: ageInput.bottomAnchor).isActive = true
    genderInput.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
    genderInput.heightAnchor.constraint(equalToConstant: 60).isActive = true

    inputsContainerView.addSubview(aboutInput)
    aboutInput.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor).isActive = true
    aboutInput.topAnchor.constraint(equalTo: genderInput.bottomAnchor).isActive = true
    aboutInput.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
    aboutInput.heightAnchor.constraint(equalToConstant: 60).isActive = true

    inputsContainerView.addSubview(memberSinceInput)
    memberSinceInput.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor).isActive = true
    memberSinceInput.topAnchor.constraint(equalTo: aboutInput.bottomAnchor).isActive = true
    memberSinceInput.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
    memberSinceInput.heightAnchor.constraint(equalToConstant: 60).isActive = true

加载视图后,我获取数据并使用以下函数调整关于我文本视图框架的大小:

func resizeTextView(_ textView: UITextView) {
    let fixedWidth = textView.frame.size.width
    textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
    let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
    var newFrame = textView.frame
    newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
    textView.frame = newFrame
}

如果我是你,我会使用 UITableView 创建此表单并在单元格内添加标签和 UITextView。

您可以像下面那样执行 UITableViewCell,我将标签的高度设置为 60 并自动布局。 UITextView 也使用自动布局并适合单元格的底部。

import UIKit

class UserDetailCell: UITableViewCell {

    var userDetailLabel : UILabel = {
        var label = UILabel()
        label.numberOfLines = 0
        label.translatesAutoresizingMaskIntoConstraints = false
        label.textColor = UIColor.lightGray
        return label
    }()

    var userDetailTextView : UITextView = {
        var tv = UITextView()
        tv.translatesAutoresizingMaskIntoConstraints = false
        tv.isScrollEnabled = false
        return tv
    }()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        setupUI()
    }

    func setupUI(){
        addSubview(userDetailLabel)

        NSLayoutConstraint.activate([
                userDetailLabel.topAnchor.constraint(equalTo: topAnchor),
                userDetailLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 8),
                userDetailLabel.rightAnchor.constraint(equalTo: rightAnchor),
                userDetailLabel.heightAnchor.constraint(equalToConstant: 60)
            ])

        addSubview(userDetailTextView)
        NSLayoutConstraint.activate([
            userDetailTextView.topAnchor.constraint(equalTo: userDetailLabel.bottomAnchor),
            userDetailTextView.leftAnchor.constraint(equalTo: leftAnchor, constant: 8),
            userDetailTextView.rightAnchor.constraint(equalTo: rightAnchor),
            userDetailTextView.bottomAnchor.constraint(equalTo: bottomAnchor)
            ])
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

那么您的 UIViewController 应该如下所示。我在 cellForRowAt indexPath 方法中将委托设置为 UITextView。由于我设置了委托,因此将调用 textViewDidChange 委托方法。它写在扩展中。

import UIKit

class UserDetailsController: UITableViewController {

    let cellId = "cell"
    var person = Person(myAge: 20, myGender: "Male", aboutMe: "Hello my name is jake waisee. What is your name? goayngeHello my name is jake waisee. What is your name? goayngeHello my name is jake waisee. What is your name? goayngeHello my name is jake waisee. What is your name? goaynge")

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(UserDetailCell.self, forCellReuseIdentifier: cellId)
        tableView.rowHeight = UITableView.automaticDimension
        tableView.estimatedRowHeight = 100
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return 3
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! UserDetailCell
        cell.userDetailTextView.delegate = self
        cell.userDetailTextView.tag = indexPath.row
        if indexPath.row == 0{
            cell.userDetailLabel.text = "Age"
            cell.userDetailTextView.text = "\(person.age)"
        }else if indexPath.row == 1{
            cell.userDetailLabel.text = "Gender"
            cell.userDetailTextView.text = person.gender
        }else if indexPath.row == 2{
            cell.userDetailLabel.text = "About me"
            cell.userDetailTextView.text = person.aboutMe
        }

        return cell
    }

}


extension UserDetailsController: UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        print(textView.text)
        if textView.tag == 2 {
            person.aboutMe = textView.text
        }else if textView.tag == 0 {
            person.age = Int(textView.text) ?? 0
        }else if textView.tag == 1 {
            person.gender = textView.text
        }

        //this will keep the textview growing as we type
        tableView.beginUpdates()
        tableView.endUpdates()
    }
}

希望这对您有所帮助。您的 UI 应该如下所示。