我可以通过在 TextView 中绑定一个变量来实现这一点,封装视图使用该变量来设置框架高度。这是最小的 TextView 实现:
struct TextView: UIViewRepresentable {
@Binding var text: String?
@Binding var attributedText: NSAttributedString?
@Binding var desiredHeight: CGFloat
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UITextView {
let uiTextView = UITextView()
uiTextView.delegate = context.coordinator
// Configure text view as desired...
uiTextView.font = UIFont(name: "HelveticaNeue", size: 15)
return uiTextView
}
func updateUIView(_ uiView: UITextView, context: Context) {
if self.attributedText != nil {
uiView.attributedText = self.attributedText
} else {
uiView.text = self.attributedText
}
// Compute the desired height for the content
let fixedWidth = uiView.frame.size.width
let newSize = uiView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
DispatchQueue.main.async {
self.desiredHeight = newSize.height
}
}
class Coordinator : NSObject, UITextViewDelegate {
var parent: TextView
init(_ view: TextView) {
self.parent = view
}
func textViewDidEndEditing(_ textView: UITextView) {
DispatchQueue.main.async {
self.parent.text = textView.text
self.parent.attributedText = textView.attributedText
}
}
}
}
关键是desiredHeight的绑定,它是在updateUIView中使用UIView sizeThatFits方法计算出来的。请注意,它包装在 DispatchQueue.main.async 块中,以避免 SwiftUI“在视图更新期间修改状态”错误。
我现在可以在 ContentView 中使用此视图:
struct ContentView: View {
@State private var notes: [String?] = [
"This is a short Note",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet consectetur. Morbi enim nunc faucibus a. Nunc pulvinar sapien et ligula ullamcorper malesuada proin libero.",
]
@State private var desiredHeight: [CGFloat] = [0, 0]
var body: some View {
List {
ForEach(0..<notes.count, id: \.self) { index in
TextView(
desiredHeight: self.$desiredHeight[index],
text: self.$notes[index],
attributedText: .constant(nil)
)
.frame(height: max(self.desiredHeight[index], 100))
}
}
}
}
这里,我在 String 数组中有几个注释,以及要绑定到 TextView 的desiredHeight 值数组。 TextView 的高度在 TextView 的框架修改器中设置。在此示例中,我还设置了最小高度,以便为初始编辑提供一些空间。仅当状态值之一(在本例中为注释)发生更改时,框架高度才会更新。在这里 TextView 的实现中,只有在文本视图上编辑结束时才会发生这种情况。
我尝试更新协调器中 textViewDidChange 委托函数中的文本。这会在您添加文本时更新框架高度,但使您只能在 TextView 的末尾键入文本,因为更新视图会将插入点重置到末尾!