Toggle Включение прокрутки UITextView после максимального количества строк

У меня есть uitextview subview в inputContainerView, поскольку он может отображаться в приложении для обмена сообщениями.

Программно при загрузке якорь высоты uitextview устанавливается при инициализации inputContainerView. Это ограничение отлично подходит для увеличения высоты контейнера по мере ввода большего количества строк текста.

Моя цель - ограничить высоту uitextview после достижения количества строк X, где любые строки, введенные после этого, можно прокручивать. И точно так же, когда количество строк падает ниже максимального, он возвращается к своей первоначальной форме — без возможности прокрутки и автоматического изменения высоты в зависимости от содержимого.

После нескольких испытаний и исследований мне удалось зафиксировать высоту после достижения максимального количества строк, но я не могу понять, как вернуть ее в исходную форму, когда количество строк упало ниже максимального. Кажется, что высота uitextview остается на высоте, на которой максимальное количество строк.

Ниже приведен соответствующий код:

//Container View Initialization, onLoad Frame Height is set to 60
override init(frame: CGRect) {
super.init(frame: frame)
autoresizingMask = .flexibleHeight

addSubview(chatTextView)
textView.heightAnchor.constraint(greaterThanOrEqualToConstant: frame.height - 20).isActive = true
}

//TextView Delegate

var isTextViewOverMaxHeight = false
var textViewMaxHeight: CGFloat = 0.0

func textViewDidChange(_ textView: UITextView) {
    let numberOfLines = textView.contentSize.height/(textView.font?.lineHeight)!

    if Int(numberOfLines) > 5 {

        if !isTextViewOverMaxHeight {
            containerView.textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 40).isActive = false
            containerView.textView.heightAnchor.constraint(equalToConstant: 
            containerView.textView.frame.height).isActive = true
            containerView.textView.isScrollEnabled = true                

            textViewMaxHeight = containerView.textView.frame.height
            isTextViewOverMaxHeight = true
        }
    } else {

        if isTextViewOverMaxHeight {
            containerView.textView.heightAnchor.constraint(equalToConstant: textViewMaxHeight).isActive = false
            containerView.textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 40).isActive = true
            containerView.textView.isScrollEnabled = false                

            isTextViewOverMaxHeight = false
        }
    }
}

person Chris    schedule 23.05.2020    source источник
comment
Это решило вашу проблему?   -  person Sandeep Bhandari    schedule 23.05.2020


Ответы (2)


Вы слишком усложнили простую проблему, вот как вы можете достичь того, чего хотите

class ViewController: UIViewController {
    var heightConstraint: NSLayoutConstraint!
    var heightFor5Lines: CGFloat = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        let textView = UITextView(frame: CGRect.zero)
        textView.delegate = self
        textView.backgroundColor = UIColor.red
        textView.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(textView)
        textView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
        textView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
        heightConstraint = textView.heightAnchor.constraint(equalToConstant: 30.0)
        heightConstraint.isActive = true
    }
}


extension ViewController: UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        let numberOfLines = textView.contentSize.height/(textView.font?.lineHeight)!

        if Int(numberOfLines) > 5 {
            self.heightConstraint.constant = heightFor5Lines
        } else {
            if Int(numberOfLines) == 5 {
                self.heightFor5Lines = textView.contentSize.height
            }
            self.heightConstraint.constant = textView.contentSize.height
        }
        textView.layoutIfNeeded()
    }
}

введите описание изображения здесь

Как это работает?

Это просто, ваш textView начинается с некоторой высоты (здесь необходимо ограничение высоты, потому что я не отключил его прокрутку и не предоставил нижнее ограничение, поэтому у него недостаточно данных для оценки его внутренней высоты) и каждый раз, когда текст изменяется вы проверяете количество строк, если количество строк меньше порогового количества строк, вы продолжаете увеличивать ограничение высоты вашего textView, чтобы его фрейм соответствовал contentSize (следовательно, без прокрутки), и как только он достигает ожидаемого количества строк , вы ограничиваете высоту, так что рамка textView меньше фактического размера содержимого, поэтому прокручивается автоматически

Надеюсь это поможет

person Sandeep Bhandari    schedule 23.05.2020

Также можно отключить исходный textView isScrollEnabled, а затем реализовать изменение размера текстового представления следующим образом:

private var heightConstraint: NSLayoutConstraint?
private let inputLinesScrollThreshold = 5

func textViewDidChange(_ textView: UITextView) {
    
    let isConstraintActive = heightConstraint.flatMap { $0.isActive } ?? false
    
    let lineHeight = textView.font?.lineHeight ?? 1
    let linesCount = Int(textView.contentSize.height / lineHeight)
    
    if isConstraintActive == false {
        heightConstraint = textView.heightAnchor.constraint(equalToConstant: textView.frame.height)
        heightConstraint?.isActive = true
        textView.isScrollEnabled = true
    } else {
        heightConstraint?.constant = linesCount > inputLinesScrollThreshold ?
            lineHeight * CGFloat(inputLinesScrollThreshold) : textView.contentSize.height
    }
    textView.layoutIfNeeded()
}
person Andrey Volobuev    schedule 14.07.2021