Toggle 在最大行数后启用 UITextView 滚动

Posted

技术标签:

【中文标题】Toggle 在最大行数后启用 UITextView 滚动【英文标题】:Toggle Enabling UITextView Scroll After Max Number of Lines 【发布时间】:2020-05-23 08:00:27 【问题描述】:

我在 inputContainerView 中有一个 uitextview subview,因为它可能出现在消息传递应用程序中。

以编程方式,在加载时,uitextview 的高度锚点在 inputContainerView 初始化时设置。当键入更多的文本行时,此约束在增加容器高度方面非常有效。

我的目标是在达到 X 行后限制 uitextview 的高度,此后键入的任何行都可以滚动。同样,当行数低于最大值时,它会返回其原始形式 - 不可滚动并根据内容自动调整高度。

经过多次试验和研究,一旦达到最大行数,我已经设法获得固定的高度,但是一旦行数下降到以下,我似乎无法弄清楚如何将其恢复为原始形式最大。 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
        
    

【问题讨论】:

解决了你的问题吗? 【参考方案1】:

你把一个简单的问题复杂化了,这里是你如何实现你想要的

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 框架小于实际内容大小,因此会自动滚动

希望对你有帮助

【讨论】:

【参考方案2】:

也可以禁用初始 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()

【讨论】:

以上是关于Toggle 在最大行数后启用 UITextView 滚动的主要内容,如果未能解决你的问题,请参考以下文章

在X行数后插入

移动端文本超出设定行数后省略的方法

PHP 插入X行数后

设置行数后集合视图水平滚动? ios 斯威夫特

CSS文本超出指定行数后省略号显示

Android TextView 常见问题与使用总结