可调整大小然后可滚动的 UITextView,如 Telegram
Resizeable then scrollable UITextView like Telegram
我想创建可以同时调整大小和滚动的 UITextView ,就像 Telegram 、 Instagram 或 Whats App 上的 UITextView 允许 UITextView 增长到 8 行然后如果你向它添加更多文本就可以滚动我能够使 UITextView 增长到 5 行,但是如果它们是更多的文本我看不到,因为 isScroll 属性 被禁用
我的 UITextView 在 UIView 内部,左右两个按钮,如果可能的话,我更愿意通过约束来实现,如果不通过代码也可以的话
您可以通过以下步骤达到预期的效果:
- 将 textView 委托分配给您的控制器
- 默认禁用 textView 滚动
- 在 textViewDidChange 委托方法上根据 textView 框架测量文本高度
- 为 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 的出口
- 添加高度限制并为其设置出口
- 实现
textViewDidChange
textView的委托方法
- 在
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()
}
}
我想创建可以同时调整大小和滚动的 UITextView ,就像 Telegram 、 Instagram 或 Whats App 上的 UITextView 允许 UITextView 增长到 8 行然后如果你向它添加更多文本就可以滚动我能够使 UITextView 增长到 5 行,但是如果它们是更多的文本我看不到,因为 isScroll 属性 被禁用
我的 UITextView 在 UIView 内部,左右两个按钮,如果可能的话,我更愿意通过约束来实现,如果不通过代码也可以的话
您可以通过以下步骤达到预期的效果:
- 将 textView 委托分配给您的控制器
- 默认禁用 textView 滚动
- 在 textViewDidChange 委托方法上根据 textView 框架测量文本高度
- 为 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 的出口
- 添加高度限制并为其设置出口
- 实现
textViewDidChange
textView的委托方法 - 在
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()
}
}