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

问题描述

我在 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 首先计算正确的高度,然后用不正确的高度替换它。如果我在 printnewSize recalculateHeight(),当我的视图加载时它会像这样:

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

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

enter image description here

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

enter image description here

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

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

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

解决方法

我花了很长时间才找到解决方案。事实证明 details: "Not a valid origin for the client: http://localhost has not been whitelisted for client ID xxxx.apps.googleusercontent.com . Please go to https://console.developers.google.com/ and whitelist this origin for your project's client ID." error: "idpiframe_initialization_failed" 大小调整逻辑很好。这是一个显示我的视图的父动画,它导致 UITextView 再次以过渡中的 updateUIView 大小值触发。

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