可调整大小的 UITextView 的 sizeThatFits 在 UIViewRepresentable 中给出了错误的大小

Posted

技术标签:

【中文标题】可调整大小的 UITextView 的 sizeThatFits 在 UIViewRepresentable 中给出了错误的大小【英文标题】:Resizable UITextView Has sizeThatFits That Gives Wrong Size in UIViewRepresentable 【发布时间】:2021-03-10 04:57:36 【问题描述】:

我在 SwiftUI 应用程序中使用UITextView,以便根据以下答案获取可编辑的多行文本字段列表:How do I create a multiline TextField in SwiftUI?

我在 SwiftUI 中这样使用组件:

@State private var textHeight: CGFloat = 0
...
GrowingField(text: $subtask.text ?? "", height: $textHeight, changed:
  print("Save...")
)
.frame(height: textHeight)

GrowingField 的定义如下:

struct GrowingField: UIViewRepresentable 
  @Binding var text: String
  @Binding var height: CGFloat
  var changed:(() -> Void)?

  func makeUIView(context: Context) -> UITextView 
    let textView = UITextView()
    textView.delegate = context.coordinator
    textView.isScrollEnabled = false
    textView.backgroundColor = .orange //For debugging
    //Set the font size and style...
  
    textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
    return textView
  

  func updateUIView(_ uiView: UITextView, context: Context) 
    if uiView.text != self.text
      uiView.text = self.text
    
    recalculateHeight(textView: uiView, height: $height)
  

  func recalculateHeight(textView: UITextView, height: Binding<CGFloat>) 
    
    let newSize = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat.greatestFiniteMagnitude))

    if height.wrappedValue != newSize.height 
      DispatchQueue.main.async 
        height.wrappedValue = newSize.height
      
    
  

  //Coordinator and UITextView delegates...

我遇到的问题是sizeThatFits 首先计算正确的高度,然后用不正确的高度替换它。如果我 print newSizerecalculateHeight() 内,当我的视图加载时会这样:

(63.0, 34.333333333333336) <!-- Right
(3.0, 143.33333333333334) <!-- Wrong
(3.0, 143.33333333333334) <!-- Wrong

我不知道错误的尺寸是从哪里来的,我也不知道为什么要替换正确的尺寸。这是高度太大时的样子:

如果我对其进行更改,recalculateHeight() 方法会再次通过 textViewDidChange() 调用,并且它会自行处理:

这真的很hacky,但如果我在makeUIView() 中设置一个计时器,它也会自行修复:

//Eww, gross...
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false)  _ in
  recalculateHeight(view: textView, height: $height)

知道如何确定不正确的sizeThatFits 值来自何处以及如何修复它吗?

【问题讨论】:

【参考方案1】:

我花了很长时间才找到解决方案。事实证明UITextView 大小调整逻辑很好。这是一个父动画,它展示了我的视图,它导致updateUIView 再次以过渡中的UITextView 大小值触发。

通过在包含我所有文本字段的父 VStack 上设置 .animation(.none),它停止了动画的传播,现在它可以工作了。 ?

【讨论】:

以上是关于可调整大小的 UITextView 的 sizeThatFits 在 UIViewRepresentable 中给出了错误的大小的主要内容,如果未能解决你的问题,请参考以下文章

可调整大小视图的圆角

如何制作可调整大小的矩形选择工具?

可调整大小的居中圆形 UIView

防止jquery draggable跳入可调整大小的droppable

在可拖动和可调整大小的 Jquery div 中删除

为啥手动调整 Visjs 时间线图的高度(可调整大小)不起作用?