Swift 更改对象后更新自动布局';s帧大小

Swift 更改对象后更新自动布局';s帧大小,swift,xcode,ios-autolayout,Swift,Xcode,Ios Autolayout,我正在使用自动布局创建一个视图,结果如下 加载视图后,我获取一些文本数据并填充UITextView。“关于我”项可以是多行,因此我可以调整特定帧的大小。然后,我得到了以下结果 看到“关于我”文本视图如何覆盖下一个字段了吗?如何使用新的“关于我”文本视图大小调整自动布局的大小?我搜索并找到了一些使用setNeedsLayout和layoutIfNeeded的建议,但都没有奏效 我正在设置自动布局,如下所示: inputsContainerView.addSubview(ageInput

我正在使用自动布局创建一个视图,结果如下

加载视图后,我获取一些文本数据并填充UITextView。“关于我”项可以是多行,因此我可以调整特定帧的大小。然后,我得到了以下结果

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

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

    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
加载视图后,我使用以下函数获取数据并调整about me textview框架的大小:

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
delegate方法。它写在一个扩展中

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应该如下所示。

您将自动布局与直接设置框架混合在一起。你应该做另一个。在这种情况下,您可以存储高度约束并更新其常量,而不是直接设置框架。@SupporterOfTruth您可以给出一个简单的示例来说明如何执行此操作吗?我尝试只设置textview的高度约束,然后在包含它的视图上调用updateConstraint。它似乎不起作用。我这样做对吗?
UITableView
答案可能是一个更好的解决方案,但您可以这样存储高度约束
heightConstraint=aboutInput.heightAnchor.constraint(equalToConstant:60)
(别忘了激活它)。然后,稍后将其常数更改为新高度,如下所示
heightConstraint.constant=newHeight
。感谢您提供详细答案。我要试试这个!我试过了,成功了!现在我修改了代码,以便将tableView.dataSource设置为名为ProfileViewModel的外部模型。UITableViewDataSource是在ProfileViewModel及其cellForRowAt函数中定义的,我无法执行
cell.userDetailTextView.delegate=self
,因为此处的self将是ProfileViewModel。是否可以设置UserDetailsController中定义的委托?