SwiftUI 包装的 SearchBar 无法关闭键盘

SwiftUI Wrapped SearchBar Can't Dismiss Keyboard

我正在使用 UIViewRepresentable 将搜索栏添加到 SwiftUI 项目。搜索栏 用于搜索主列表 - 我已经设置了搜索逻辑并且工作正常, 但是我无法将键盘编码为在搜索时消失 取消。取消按钮没有响应。如果我单击文本字段 clearButton 搜索结束,完整列表出现,但键盘没有消失。 如果我取消注释 textDidChange 中的 resignFirstResponder 行,则行为如下 预期,除了键盘在每个字符后消失。

这是搜索栏:

import Foundation
import SwiftUI

struct MySearchBar: UIViewRepresentable {
    @Binding var sText: String

    class Coordinator: NSObject, UISearchBarDelegate {
        @Binding var sText: String

        init(sText: Binding<String>) {
            _sText = sText
        }

        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            sText = searchText
            //this works for EVERY character
            //searchBar.resignFirstResponder()
        }
    }

    func makeCoordinator() -> MySearchBar.Coordinator {
        return Coordinator(sText: $sText)
    }

    func makeUIView(context: UIViewRepresentableContext<MySearchBar>) -> UISearchBar {
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator
        searchBar.showsCancelButton = true
        return searchBar
    }

    func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext<MySearchBar>) {
        uiView.text = sText
    }

    func searchBarCancelButtonClicked(searchBar: UISearchBar) {
        //this does not work
        searchBar.text = ""
        //none of these work

        searchBar.resignFirstResponder()
        searchBar.showsCancelButton = false
        searchBar.endEditing(true)
    }
}

然后我在列表中的 SwiftUI 中加载了一个 MySearchBar。

var body: some View {
    NavigationView {
        List {
            MySearchBar(sText: $searchTerm)
            if !searchTerm.isEmpty {

                ForEach(Patient.filterForSearchPatients(searchText: searchTerm)) { patient in
                    NavigationLink(destination: EditPatient(patient: patient, photoStore: self.photoStore, myTextViews: MyTextViews())) {
                        HStack(spacing: 30) {

                        //and the rest of the application

Xcode 版本 11.2 beta 2 (11B44)。斯威夫特用户界面。我已经在模拟器和 设备。任何指导将不胜感激。

未调用 searchBarCancelButtonClicked 的原因是它在 MySearchBar 中,但您已将 Coordinator 设置为搜索栏委托。如果将 searchBarCancelButtonClicked 函数移动到 Coordinator,它将被调用。

协调器应如下所示:

class Coordinator: NSObject, UISearchBarDelegate {
    @Binding var sText: String

    init(sText: Binding<String>) {
        _sText = sText
    }

    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        sText = searchText
    }

    func searchBarCancelButtonClicked(searchBar: UISearchBar) {

        searchBar.text = ""

        searchBar.resignFirstResponder()
        searchBar.showsCancelButton = false
        searchBar.endEditing(true)
    }
}

searchBarCancelButtonClicked 调用将传递给设置为协调器的 UISearchBar 委托,因此将 func searchBarCancelButtonClicked 放在那里。

此外,当您清除文本时,您不应该设置 searchBar.text = "",这是直接设置 UISearchBars 文本 属性 的实例,而是清除您的协调器 属性 text。通过这种方式,您的 SwiftUI 视图将注意到由于 @Binding 属性 包装器而发生的变化,并且知道是时候更新了。

这是“MySearchBar”的完整代码:

import UIKit
import SwiftUI

struct MySearchBar : UIViewRepresentable {

    @Binding var text : String

    class Coordinator : NSObject, UISearchBarDelegate {

        @Binding var text : String

        init(text : Binding<String>) {
            _text = text
        }

        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            text = searchText
            searchBar.showsCancelButton = true
        }

        func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
            text = ""
            searchBar.showsCancelButton = false
            searchBar.endEditing(true)
        }
    }

    func makeCoordinator() -> SearchBar.Coordinator {
        return Coordinator(text: $text)
    }

    func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator
        return searchBar
    }

    func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext<SearchBar>) {
        uiView.text = text
    }
}