首页 > 解决方案 > 当 TextView 的 isScrollEnabled 设置为 false 时自动布局的意外行为

问题描述

我正在尝试制作不断增长的 textview 并使其在某些内容大小下可滚动。我正在做的是:

func textViewDidChange(_ textView: UITextView) {
        if textView.contentSize.height > 100 && !textView.isScrollEnabled {
            let frame = textView.frame
            textView.isScrollEnabled = true
            let heightConstraint: NSLayoutConstraint = .init(item: textView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: frame.height)
            heightConstraint.identifier = "height"
            textView.addConstraint(heightConstraint)
        }
        
        if textView.contentSize.height < 100 && textView.isScrollEnabled {
            textView.isScrollEnabled = false
            let heightConstraint = textView.constraints.first { constraint in
                constraint.identifier == "height"
            }
            textView.removeConstraint(heightConstraint!)
        }
        print(textView.contentSize.height, textView.frame.height)
    }

如果内容大小大于 100,我启用滚动并添加高度约束

如果内容大小小于 100,我禁用滚动并删除约束(我希望 textview 适合其内容,就像禁用滚动时通常那样)

我启用滚动没有问题,但是当 contentsize 小于 100 时,第二个 if 语句会触发,并且 textview 出于某种原因占用了整个屏幕空间。当我再次调用 textViewDidChange (通过删除或添加 smth 到 textview)时,ifs 都会触发并且一切正常。

我试图做的是打电话textview.sizeToFit()view.layoutIfNeeded()没有成功。我在这里做错了什么?

标签: swiftautolayoutuikit

解决方案


我认为你做的比你需要做的要多得多。

更好的方法是创建高度约束,等于常数值 100,然后根据需要激活/取消激活它。

试试这样:

class ViewController: UIViewController, UITextViewDelegate {
    
    let myTextView = UITextView()
    
    var tvHeightConstraint: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        myTextView.translatesAutoresizingMaskIntoConstraints = false
        myTextView.font = .systemFont(ofSize: 18.0)
        myTextView.backgroundColor = .yellow
        
        view.addSubview(myTextView)
        
        let g = view.safeAreaLayoutGuide
        
        tvHeightConstraint = myTextView.heightAnchor.constraint(equalToConstant: 100.0)
        
        NSLayoutConstraint.activate([
            myTextView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
            myTextView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
            myTextView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
        ])
        
        myTextView.isScrollEnabled = false
        
        myTextView.delegate = self
    }

    func textViewDidChange(_ textView: UITextView) {
        textView.isScrollEnabled = (textView.contentSize.height > 100)
        tvHeightConstraint.isActive = textView.isScrollEnabled
    }
    
}

推荐阅读