use*_*787 9 uitextview ios swift swiftui
我想弄清楚如何使 UITextView 大小依赖于它在 SwiftUI 中的内容。我将 UITextView 包装UIViewRepresentable如下:
struct TextView: UIViewRepresentable {
@Binding var showActionSheet: Bool
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UITextView {
let uiTextView = UITextView()
uiTextView.delegate = context.coordinator
uiTextView.font = UIFont(name: "HelveticaNeue", size: 15)
uiTextView.isScrollEnabled = true
uiTextView.isEditable = true
uiTextView.isUserInteractionEnabled = true
uiTextView.backgroundColor = UIColor(white: 0.0, alpha: 0.05)
uiTextView.isEditable = false
return uiTextView
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.attributedText = prepareText(question: question)
var frame = uiView.frame
frame.size.height = uiView.contentSize.height
uiView.frame = frame
}
func prepareText(text: string) -> NSMutableAttributedString {
...................
return attributedText
}
class Coordinator : NSObject, UITextViewDelegate {
var parent: TextView
init(_ view: TextView) {
self.parent = view
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
parent.showActionSheet = true
return false
}
}
}
Run Code Online (Sandbox Code Playgroud)
此外,我尝试根据内容大小更改 updateUIView 中的帧大小,但没有任何效果。我想在这个阶段,视图甚至没有布局,它的框架在其他地方被覆盖。如果有人能指出我正确的方向,我将不胜感激。
小智 9
我能够通过在封装视图使用的 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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
关键是所需高度的绑定,它是在 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))
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我在 String 数组中有几个注释,以及要绑定到 TextView 的一组所需高度值。TextView 的高度在 TextView 上的框架修改器中设置。在这个例子中,我还设置了一个最小高度,为初始编辑留出一些空间。框架高度仅在状态值之一(在本例中为注释)更改时更新。在此处的 TextView 的实现中,这仅在文本视图上结束编辑时发生。
我尝试更新协调器中 textViewDidChange 委托函数中的文本。这会在您添加文本时更新框架高度,但使您只能在 TextView 的末尾键入文本,因为更新视图会将插入点重置到末尾!