菜鸟教程小白 发表于 2022-12-11 20:47:28

ios - 更改高度时,UITextView 的 textContainer 在错误的帧处呈现


                                            <p><p>我想要的只是在您键入/粘贴时调整 <code>UITextView</code> 的大小。它应该是可滚动的,因为我不希望 <code>UITextView</code> 填满屏幕。用这几行代码就可以轻松实现。</p>

<pre><code>@IBOutlet weak var mainTextView: UITextView!
@IBOutlet weak var mainTextViewHeightConstraint: NSLayoutConstraint!

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

// This method is used for calculating the string&#39;s height in a UITextField
func heightOf(text: String, for textView: UITextView) -&gt; CGFloat {
    let nsstring: NSString = text as NSString
    let boundingSize = nsstring.boundingRect(
      with: CGSize(width: textView.frame.size.width, height: .greatestFiniteMagnitude),
      options: .usesLineFragmentOrigin,
      attributes: [.font: textView.font!],
      context: nil).size
    return ceil(boundingSize.height + textView.textContainerInset.top + textView.textContainerInset.bottom)
}

// This method calculates the UITextView&#39;s new height
func calculateHeightFor(text: String, in textView: UITextView) -&gt; CGFloat {
    let newString: String = textView.text ?? &#34;&#34;
    let minHeight = self.heightOf(text: &#34;&#34;, for: textView) // 1 line height
    let maxHeight = self.heightOf(text: &#34;\n\n\n\n\n&#34;, for: textView) // 6 lines height
    let contentHeight = self.heightOf(text: newString, for: textView) // height of the new string
    return min(max(minHeight, contentHeight), maxHeight)
}

// The lines inside will change the UITextView&#39;s height
func textViewDidChange(_ textView: UITextView) {
    self.mainTextViewHeightConstraint.constant = calculateHeightFor(
      text: textView.text ?? &#34;&#34;,
      in: textView)
}
</code></pre>

<p>这非常有效,除非您粘贴多行文本,或按 <strong>enter</strong>(换行符)。</p>

<hr/>

<p>为了解决粘贴问题,各种 SO 问题建议我创建 <code>UITextView</code> 的子类来覆盖 <code>paste(_:)</code> 方法,或者我使用 <code>textView(_: shouldChangeTextIn....)</code> 委托(delegate)方法。经过几次实验,最好的答案是使用 <code>shouldChangeTextIn</code> 方法,这导致我的代码变成了这个</p>

<pre><code>// I replaced `textViewDidChange(_ textView: UITextView)` with this
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -&gt; Bool {
    self.mainTextViewHeightConstraint.constant = calculateHeightFor(
      text: ((textView.text ?? &#34;&#34;) as NSString).replacingCharacters(in: range, with: text),
      in: textView)
    return true
}
</code></pre>

<hr/>

<p>现在应该发生的是,当您粘贴文本时,<code>UITextView</code> 应该如下所示。 (粘贴的字符串是“A\nA\nA\nA\nA”或 5 行只是 A)</p>

<p> <a href="/image/zpAth.png" rel="noreferrer noopener nofollow"><img src="/image/zpAth.png" alt="enter image description here"/></a> </p>

<p>可是变成了这个样子</p>

<p> <a href="/image/6uFSu.png" rel="noreferrer noopener nofollow"><img src="/image/6uFSu.png" alt="enter image description here"/></a> </p>

<p>从截图中可以看出,textContainer 的框架在错误的位置。现在奇怪的是,它似乎只在你粘贴到一个空的 <code>UITextView</code> 时才会发生。</p>

<p>我尝试过设置和重置 <code>UITextView</code> 的 frame.size,我尝试过手动设置 <code>NSTextContainer</code> 的大小以及其他一些 hacky 解决方案,但是我似乎无法修复它。我该如何解决这个问题?</p>

<p>附加信息:</p>

<p>查看 View 调试器后,输入 <strong>enter</strong>(换行符)时的外观如下所示</p>

<p> <a href="/image/gdf1N.png" rel="noreferrer noopener nofollow"><img src="/image/gdf1N.png" alt="enter image description here"/></a>
<a href="/image/ivQRM.png" rel="noreferrer noopener nofollow"><img src="/image/ivQRM.png" alt="enter image description here"/></a> </p>

<p>如我们所见,文本容器的位置错误。</p>

<hr/>

<p>毕竟添加 <code>UIView.animate</code>block 似乎解决了一些问题,但不是全部。为什么会这样?</p>

<pre><code>// These snippet kind of fixes the problem
self.mainTextViewHeightConstraint.constant = calculateHeightFor(
    text: textView.text ?? &#34;&#34;,
    in: textView)
UIView.animate(withDuration: 0.1) {
    self.view.layoutIfNeeded()
}
</code></pre>

<p>注意:我没有放置 <code>UIView.animate</code> 解决方案,因为它没有涵盖所有的错误。</p>

<p><strong>注意:</strong></p>

<p>操作系统支持:iOS 8.xx - iOS 12.xx
Xcode:v10.10
Swift:3 和 4(我都试过了)</p>

<p><strong>PS:</strong>是的,我已经处理过其他一些 SO 问题,例如底部列出的问题和其他一些问题</p>

<ul>
<li> <a href="https://stackoverflow.com/questions/32913105/textcontainer-isnt-resizing-while-changing-bounds-of-uitextview" rel="noreferrer noopener nofollow">TextContainer isn&#39;t resizing while changing bounds of UITextView</a> </li>
<li> <a href="https://stackoverflow.com/questions/21889657/uitextviews-text-going-beyond-bounds" rel="noreferrer noopener nofollow">UITextView&#39;s text going beyond bounds</a> </li>
<li> <a href="https://stackoverflow.com/questions/51770900/uitextview-stange-animation-glitch-on-paste-action-ios11" rel="noreferrer noopener nofollow">UITextView stange animation glitch on paste action (iOS11)</a> </li>
<li> <a href="https://stackoverflow.com/questions/39268477/how-to-calculate-textview-height-base-on-text" rel="noreferrer noopener nofollow">How to calculate TextView height base on text</a> </li>
</ul></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>可以忽略所有计算高度的代码,使用设置textview属性scrolling Enabled = false
textview 将自行调整以适应文本内容
<a href="/image/wUGtg.png" rel="noreferrer noopener nofollow">image1</a> </p>

<p>然后根据需要更改代码</p>

<pre><code>@IBOutlet weak var textView: UITextView!

override func viewDidLoad() {
    super.viewDidLoad()
    self.textView.text = &#34;A\nA\nA\nA\nA&#34;
}
</code></pre>

<p>结果会是这样
<a href="/image/gvG8c.png" rel="noreferrer noopener nofollow">image2</a> </p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 更改高度时,UITextView 的 textContainer 在错误的帧处呈现,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/53206469/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/53206469/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 更改高度时,UITextView 的 textContainer 在错误的帧处呈现