SwiftUI Wrapped SearchBar не может закрыть клавиатуру

Я использую UIViewRepresentable, чтобы добавить панель поиска в проект SwiftUI. Панель поиска предназначена для поиска в основном списке - я настроил логику поиска, и она работает нормально, однако мне не удалось закодировать исчезновение клавиатуры при отмене поиска. Кнопка Отмена не реагирует. Если я щелкну текстовое поле clearButton, поиск будет завершен и появится полный список, но клавиатура не исчезнет. Если я раскомментирую строку resignFirstResponder в textDidChange, поведение будет таким, как ожидалось, за исключением того, что клавиатура исчезает после каждого символа.

Вот строка поиска:

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)
    }
}

И я загружаю MySearchBar в SwiftUI в список.

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 бета 2 (11B44). SwiftUI. Я тестировал на симуляторе и на устройстве. Любое руководство будет оценено.

2 ответа

Решение

Причина 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 звонок будет передан UISearchBars делегат, который установлен как координатор, поэтому поместите func searchBarCancelButtonClicked вместо этого.

Кроме того, когда вы очищаете текст, вы не должны устанавливать searchBar.text = "", который устанавливает экземпляр UISearchBars text свойство напрямую, но вместо этого очистите свойство Coordinators text. Таким образом ваш SwiftUI View заметит изменение из-за@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
    }
}
Другие вопросы по тегам