工具栏显示我是否使用 TextField,但不显示 UITextView。我不确定这是否是一个错误,或者我只是没有正确地将 UITextView 与 SwiftUI 桥接。关于如何使 .toolbar() 与 UITextView 一起使用有什么想法吗?这是我的代码:
struct MyUITextView: UIViewRepresentable {
@Binding var text: String
private let editor = UITextView()
func makeUIView(context: Context) -> UITextView {
editor.delegate = context.coordinator
return editor
}
func makeCoordinator() -> Coordinator {
Coordinator(text: $text)
}
func updateUIView(_ editor: UITextView, context: Context) {
editor.text = text
}
class Coordinator: NSObject, UITextViewDelegate {
@Binding private var text: String
init(text: Binding<String>) {
self._text = text
}
func textViewDidChange(_ editor: UITextView) {
text = editor.text
}
}
}
struct ContentView: View {
@State var uitextView = "UITextView"
@State var textfield = "TextField"
var body: some View {
VStack {
MyUITextView(text: $uitextView) // Toolbar doesn't show up when focused
.border(.black, width: 1)
.frame(maxHeight: 40)
TextField("", text: $textfield) // Toolbar shows up when focused
.border(.black, width: 1)
}
.toolbar {
ToolbarItem(placement: .keyboard) {
Button("Click") {}
}
}
}
}
SwiftUI 的
toolbar
不了解 UIKit 视图,因此它不会向您的 UITextView
添加工具栏。
您仍然可以使用 UIKit API 添加工具栏:
let toolbar = UIToolbar()
toolbar.items = [...]
editor.inputAccessoryView = toolbar
toolbar.translatesAutoresizingMaskIntoConstraints = false
如果你想使用 SwiftUI 编写工具栏的内容,你必须在协调器中添加一个
UIHostingController
。
出于某种原因,添加单个
UIBarButtonItem(customView: hostingController.view)
会使用户无法按 SwiftUI Button
。您必须将整个inputAccessoryView
改为SwiftUI。
示例:
struct MyUITextView<Toolbar: View>: UIViewRepresentable {
init(text: Binding<String>, @ViewBuilder toolbar: @escaping () -> Toolbar) {
self._text = text
self.toolbar = toolbar
}
@Binding var text: String
let toolbar: () -> Toolbar
func makeCoordinator() -> Coordinator {
Coordinator(hostingVC: UIHostingController(rootView: toolbar()))
}
func makeUIView(context: Context) -> UITextView {
context.coordinator.editor
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.text = text
context.coordinator.stringDidChange = { string in
text = string
}
}
class Coordinator: NSObject, UITextViewDelegate {
let hostingVC: UIHostingController<Toolbar>
init(hostingVC: UIHostingController<Toolbar>) {
self.hostingVC = hostingVC
hostingVC.sizingOptions = [.intrinsicContentSize]
}
lazy var editor: UITextView = {
let editor = UITextView()
editor.delegate = self
editor.inputAccessoryView = hostingVC.view
editor.inputAccessoryView?.translatesAutoresizingMaskIntoConstraints = false
return editor
}()
var stringDidChange: ((String) -> ())?
func textViewDidChange(_ textView: UITextView) {
stringDidChange?(textView.text)
}
}
}
MyUITextView(text: $uitextView) {
// this HStack is for imitating the UIToolbar
HStack {
Button("Click") { print("Foo") }
.padding()
Spacer()
}
.background(.bar.shadow(.drop(radius: 1)))
}
.border(.black, width: 1)
.frame(maxHeight: 40)