我有一个名为composeTextView的UITextView
位于键盘正上方。这个UITextView
位于名为composeUIView的视图中。当用户输入文本时,TextView会调整大小以显示所有文本。我的问题是,当我尝试调整composeUIView的底部约束时,composeTextView的大小会停止更改以适合其内容。我不明白这里发生了什么或如何解决它。如果有人知道修复我可以使用帮助。
长话短说,我尝试显示UITextView
的更多行,因为用户增加了他们使用的行数,然后移动UITextView
所在的UIView这样显示的额外线条不会被键盘覆盖。
class ChatViewController: UIViewController, UITextViewDelegate {
@IBOutlet weak var composeTextView: UITextView!
@IBOutlet weak var composeViewBottomConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
composeTextView.delegate = self
}
func textViewDidChange(_ textView: UITextView) {
let oldHeight = composeTextView.frame.height
let fixedWidth = composeTextView.frame.size.width
composeTextView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
let newSize = composeTextView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
var newFrame = composeTextView.frame
newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
composeTextView.frame = newFrame
let newHeight = composeTextView.frame.height
let changeHeight = newHeight - oldHeight
if changeHeight != 0 {
self.composeViewBottomConstraint.constant += changeHeight
}
}
编辑1:
根据迈克尔的建议,我做了这个改变,但它不能始终如一地工作。如果我按住退格按钮并且它一次开始删除单词,它最终会以比正常的TextView小的方式结束。此外,如果我粘贴一大块文本或删除一大块文本,它没有正确回应:
var oldNumLines = CGFloat()
override func viewDidLoad() {
super.viewDidLoad()
composeTextView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
self.oldNumLines = composeTextView.contentSize.height / (composeTextView.font?.lineHeight)!
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
let newNumLines = composeTextView.contentSize.height / (composeTextView.font?.lineHeight)!
print("oldNumLines: \(oldNumLines)")
print("newNumLines: \(newNumLines)")
let diffNumLines = newNumLines - oldNumLines
print("diffNumLines: \(diffNumLines)")
let heightChange = (diffNumLines * (composeTextView.font?.lineHeight)!)
print("heightChange: \(heightChange)")
if diffNumLines > 1 {
if composeTextView.frame.size.height < (5 * (composeTextView.font?.lineHeight)!) {
composeTextView.frame.size.height += heightChange
composeViewHeightConstraint.constant += heightChange
}
}
if diffNumLines < -1 {
// the number 1.975216273089 is the first value of newNumLines
if newNumLines > 1.975216273089 && composeTextView.frame.size.height < (5 * (composeTextView.font?.lineHeight)!) {
composeTextView.frame.size.height += heightChange
composeViewHeightConstraint.constant += heightChange
}
}
if composeTextView.frame.size.height >= (5 * (composeTextView.font?.lineHeight)!) && composeTextView.frame.size.height < (6 * (composeTextView.font?.lineHeight)!) && diffNumLines < -1 {
composeTextView.frame.size.height += heightChange
composeViewHeightConstraint.constant += heightChange
}
self.oldNumLines = newNumLines
}
编辑2:
我想出了如何解决最终问题。我正在检查新旧行数(diffNumLines)的差异是否大于1或小于-1。我没有意识到有时diffNumLines大约是0.95或-95。有些情况下diffNumLines大概是.44并且我不想包含它,所以我改变了所有实例,我将diffNumLines值与1或-1进行了比较,因此它被比作0.75或-.75。然后我添加了几行,我检查heightChange是否大于5行的高度或小于5行的负高度。使用数字5实际上找不到5行的高度,我必须得到5行的实际高度。我发现在调试控制台和一些打印语句中,如果我一次输入一个单词,composeTextView会在高度为100时停止增加。它从33的高度开始,因此简单的减法告诉我们我希望它在高度是67.我设置了一些规则,所以如果heightChange&gt;如图67所示,heightChange将被设置回67并且如果heightChange&lt; -67,它将设置为-67。这最终修复了所有内容,因此它很平滑并且没有显示任何错误。
我只有最后一个不需要解决但可能有用的问题。如果我尝试设置高度变化的动画,它会显示composeTextView弹出到其新的y位置,然后动画下方向下按以填充其高度。这看起来很难看,所以我决定反对动画。我希望的是,composeView的底部会保持原样,并且它的顶部会动画起来填充它的高度。我认为这需要改变它的顶部约束而不是它的高度,我宁愿不再这样做。
我对它的情况感到满意,但还有改进的余地。
这是我的最终代码:
@IBOutlet weak var composeTextItem: UIBarButtonItem!
@IBOutlet weak var composeUIView: UIView!
var oldNumLines = CGFloat()
override func viewDidLoad() {
super.viewDidLoad()
composeTextView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
// the number 1.975216273089 is the first value of newNumLines
self.oldNumLines = 1.97521627308861
}
deinit {
composeTextView.removeObserver(self, forKeyPath: "contentSize")
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
let newNumLines = composeTextView.contentSize.height / (composeTextView.font?.lineHeight)!
let diffNumLines = newNumLines - oldNumLines
var heightChange = (diffNumLines * (composeTextView.font?.lineHeight)!)
if heightChange > 67 {
heightChange = 67
}
if heightChange < -67 {
heightChange = -67
}
if diffNumLines > 0.75 {
if composeTextView.frame.size.height < (5 * (composeTextView.font?.lineHeight)!) {
composeTextView.frame.size.height += heightChange
composeViewHeightConstraint.constant += heightChange
}
}
if composeTextView.frame.size.height > 33 {
if diffNumLines < -0.75 {
// the number 1.975216273089 is the first value of newNumLines
if newNumLines > 1.97521627308861 && composeTextView.frame.size.height < (5 * (composeTextView.font?.lineHeight)!) {
composeTextView.frame.size.height += heightChange
composeViewHeightConstraint.constant += heightChange
}
}
if composeTextView.frame.size.height >= (5 * (composeTextView.font?.lineHeight)!) && composeTextView.frame.size.height < (6 * (composeTextView.font?.lineHeight)!) && diffNumLines < -0.75 {
composeTextView.frame.size.height += heightChange
composeViewHeightConstraint.constant += heightChange
}
}
self.oldNumLines = newNumLines
}
答案 0 :(得分:2)
我不确定您为什么要尝试更改包含textview的视图的底部约束...如果您要更改composeTextView
的高度,那么您应该同时将composeView
的高度更改为相同的数量。
此外,我不会使用textViewDidChange
,而是将contentSize
的观察者添加到textview,然后只要内容大小发生变化,就会调用函数。它让你的生活变得更轻松 - 如果你正在使用Swift 4,那就是这样的事情:
composeTextView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
请务必在composeTextView.removeObserver(self, forKeyPath: "contentSize")
。
deinit
然后,覆盖observeValue
函数:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
// Change height of composeTextView and composeView here
}
适应高度变化的一个好方法是找出旧行数与新行数之间的差异,因为你知道每次调用此函数时,行数都不同。要获得行数,你可以做一些事情(Swift 4),如:
let numLines = composeTextView.contentSize.height / (composeTextView.font?.lineHeight)!
计算线条的差异,乘以composeTextView.font?.lineHeight
,然后计算你改变一切的高度。
希望这有帮助。
修改强>
如果您正确设置了约束条件,则不应该向上移动composeView
,这将超出需要的工作量。当composeView
的高度发生变化时,底部不应该移动 - 只有顶部应该移动。 当您显示键盘时,我建议您更改composeView
位置,然后再 。当你改变高度并开始输入多行时,我建议只在需要时改变高度。