SwiftUI:.toolbar 不适用于 UITextView

问题描述 投票:0回答:1

工具栏显示我是否使用 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") {}
            }
        }
    }
}

Demo

ios swift swiftui uikit uitextview
1个回答
0
投票

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)
© www.soinside.com 2019 - 2024. All rights reserved.