可调整大小然后可滚动的 UITextView,如 Telegram

Resizeable then scrollable UITextView like Telegram

我想创建可以同时调整大小和滚动的 UITextView ,就像 Telegram 、 Instagram 或 Whats App 上的 UITextView 允许 UITextView 增长到 8 行然后如果你向它添加更多文本就可以滚动我能够使 UITextView 增长到 5 行,但是如果它们是更多的文本我看不到,因为 isScroll 属性 被禁用

我的 UITextView 在 UIView 内部,左右两个按钮,如果可能的话,我更愿意通过约束来实现,如果不通过代码也可以的话

您可以通过以下步骤达到预期的效果:

  1. 将 textView 委托分配给您的控制器
  2. 默认禁用 textView 滚动
  3. 在 textViewDidChange 委托方法上根据 textView 框架测量文本高度
  4. 为 textview 分配适当的高度并在内容超出时启用滚动(在您的情况下最大高度为 8 行)

下面附上代码片段,可能对您有所帮助:

let commentViewMinHeight: CGFloat = 45.0 
let commentViewMaxHeight: CGFloat = 120.0 //In your case it should be 8 lines

func textViewDidChange(_ textView: UITextView) {
     //Calculate text height 
     let size = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat.greatestFiniteMagnitude))

     textViewHeightConstraint.constant = size.height.clamped(to: commentViewMinHeight...commentViewMaxHeight)

     if textView.contentSize.height < commentViewMaxHeight {
        textView.setContentOffset(CGPoint.zero, animated: false)
        if textView.isScrollEnabled {
           textView.isScrollEnabled = false
        }
     } else {
            if !textView.isScrollEnabled {
                textView.isScrollEnabled = true
            }
     }
} 

extension Comparable {
    func clamped(to limits: ClosedRange<Self>) -> Self {
        return min(max(self, limits.lowerBound), limits.upperBound)
    }
}

Sagar的回答很好,但我想加强一点并添加一些动画:

您需要的步骤

  • 获取 textView 的出口
  • 添加高度限制并为其设置出口
  • 实现textViewDidChangetextView的委托方法
  • textViewDidChange
    • 使用textView.sizeThatFits(size)
    • 计算新高度
    • 设置高度约束常量为新高度
    • [可选] 为约束更改设置动画以更加用户友好

这里有一个例子

class ViewController: UIViewController {

    @IBOutlet weak var textView: UITextView!
    @IBOutlet weak var textViewHeightConstraint: NSLayoutConstraint!

    let maxTextHeight:CGFloat = 200
    let minTextHeight:CGFloat = 50

    let animationDuration:Double = 0.3

    override func viewDidLoad() {
        super.viewDidLoad()
        textView.delegate = self
        resizeTextViewToFitText()
    }

    func resizeTextViewToFitText() {
        let size = CGSize(width: textView.frame.width, height: .infinity)
        let expectedSize = textView.sizeThatFits(size)
        self.textViewHeightConstraint.constant = max(min(expectedSize.height, self.maxTextHeight), self.minTextHeight)
        self.textView.isScrollEnabled = expectedSize.height > self.maxTextHeight
        UIView.animate(withDuration: animationDuration) {
            self.view.layoutIfNeeded()
        }
    }
}

extension ViewController: UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
       resizeTextViewToFitText()
    }
}