Проблема с панелью поиска SwiftUI с NavigationLink

#swiftui #searchbar #swiftui-navigationlink

#swiftui #панель поиска #swiftui-navigationlink

Вопрос:

У меня проблема в SwiftUI с появлением панели поиска. При использовании NavigationLink появляется задержка. Я видел, что проблема появляется только с NavigationLinks, если я использую условное наложение или другой «ручной» способ перемещения между представлениями, проблема не появляется. Вы знаете, что я мог бы сделать, чтобы решить проблему?

Вот мой код просмотра:

 import SwiftUI

struct ContentView: View {
    
    @State var searchText = ""
    
    var body: some View {
        
        NavigationView{
            
            NavigationLink(destination: ContentView2()){
                Text("Go to Sub View")
            }
            .navigationBarTitle("Main View")
            .add(SearchBar(text: self.$searchText, hide: true, placeholder: "Search", cancelButton: true, autocapitalization: .sentences))
        }
    }
}

struct ContentView2 : View {
    
    @State var searchText = ""
    
    var body: some View {
        
        Text("Hello, world!")
            
            .navigationBarTitle("Sub View")
            .add(SearchBar(text: self.$searchText, hide: true, placeholder: "Search", cancelButton: true, autocapitalization: .sentences))
        
    }
}
 

Мой код панели поиска

 import SwiftUI

class SearchBar: NSObject, ObservableObject {
    
    
    let searchController: UISearchController = UISearchController(searchResultsController: nil)
    
    @Binding var text: String
    let hide : Bool
    let placeholder : String
    let cancelButton : Bool
    let autocapitalization : UITextAutocapitalizationType
    
    init(text: Binding<String>, hide: Bool, placeholder: String, cancelButton: Bool, autocapitalization: UITextAutocapitalizationType) {
        
        self._text = text
        self.hide = hide
        self.placeholder = placeholder
        self.cancelButton = cancelButton
        self.autocapitalization = autocapitalization
        
        super.init()
        
        
        self.searchController.obscuresBackgroundDuringPresentation = false
        self.searchController.searchResultsUpdater = self
        
        self.searchController.hidesNavigationBarDuringPresentation = hide
        self.searchController.automaticallyShowsCancelButton = cancelButton
        self.searchController.searchBar.placeholder = placeholder
        self.searchController.searchBar.autocapitalizationType = autocapitalization
        
    }
}

extension SearchBar: UISearchResultsUpdating {
   
    func updateSearchResults(for searchController: UISearchController) {
        
        // Publish search bar text changes.
        if let searchBarText = searchController.searchBar.text {
            self.text = searchBarText
        }
    }
}

struct SearchBarModifier: ViewModifier {
    
    let searchBar: SearchBar
    
    func body(content: Content) -> some View {
        content
            .overlay(
                ViewControllerResolver { viewController in
                    viewController.navigationItem.searchController = self.searchBar.searchController
                }
                    .frame(width: 0, height: 0)
            )
    }
}

extension View {
    
    func add(_ searchBar: SearchBar) -> some View {
        return self.modifier(SearchBarModifier(searchBar: searchBar))
    }
    
}
 

Мой код ViewController

 import SwiftUI

final class ViewControllerResolver: UIViewControllerRepresentable {
    
    let onResolve: (UIViewController) -> Void
        
    init(onResolve: @escaping (UIViewController) -> Void) {
        self.onResolve = onResolve
    }
    
    func makeUIViewController(context: Context) -> ParentResolverViewController {
        ParentResolverViewController(onResolve: onResolve)
    }
    
    func updateUIViewController(_ uiViewController: ParentResolverViewController, context: Context) { }
}

class ParentResolverViewController: UIViewController {
    
    let onResolve: (UIViewController) -> Void
    
    init(onResolve: @escaping (UIViewController) -> Void) {
        self.onResolve = onResolve
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("Use init(onResolve:) to instantiate ParentResolverViewController.")
    }
        
    override func didMove(toParent parent: UIViewController?) {
        super.didMove(toParent: parent)
        if let parent = parent {
            onResolve(parent)
        }
    }
    
    override func viewDidAppear(_ animated: Bool) {
        
            self.parent?.navigationItem.hidesSearchBarWhenScrolling = false
            self.parent?.definesPresentationContext = true
            self.parent?.navigationController?.navigationBar.sizeToFit()
        
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        
            self.parent?.navigationItem.hidesSearchBarWhenScrolling = false
            self.parent?.definesPresentationContext = true
            self.parent?.navigationController?.navigationBar.sizeToFit()
        
    }


}
 

И вот видео проблемы

Ответ №1:

Установите hidesSearchBarWhenScrolling свойство перед SearchBar отображением на экране. Это можно сделать в viewWillAppear или как в примере ниже:

 struct SearchBarModifier: ViewModifier {
    let searchBar: SearchBar

    func body(content: Content) -> some View {
        content
            .overlay(
                ViewControllerResolver { viewController in
                    viewController.navigationItem.searchController = self.searchBar.searchController
                    viewController.navigationItem.hidesSearchBarWhenScrolling = false
                }
                    .frame(width: 0, height: 0)
            )
    }
}
 

Комментарии:

1. Простое размещение кода без базового объяснения не всегда полезно. Как именно ваш код отвечает на этот вопрос?