【问题标题】:SwiftUI UISearchController searchResultsController navigation stack issueSwiftUI UISearchController searchResultsController 导航堆栈问题
【发布时间】:2019-10-22 20:22:31
【问题描述】:

我有 UISearchController,它是为 SwiftUI 制作的 UIViewControllerRepresentable,如下:

struct SearchViewController<Content: View>: UIViewControllerRepresentable {
    var content: () -> Content
    let searchResultsView = SearchResultsView()

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }

    func makeUIViewController(context: Context) -> UINavigationController {

        let rootViewController = UIHostingController(rootView: content())
        let navigationController = UINavigationController(rootViewController: rootViewController)
        let searchResultsController = UIHostingController(rootView: searchResultsView)

        // Set nav properties
        navigationController.navigationBar.prefersLargeTitles = true
        navigationController.definesPresentationContext = true

        // Create search controller
        let searchController = UISearchController(searchResultsController: searchResultsController)
        searchController.searchBar.autocapitalizationType = .none
        searchController.delegate =  context.coordinator
        searchController.searchBar.delegate = context.coordinator // Monitor when the search button is tapped.

        // Create default view
        rootViewController.navigationItem.searchController = searchController
        rootViewController.title = "Search"

        return navigationController
    }

    func updateUIViewController(_ navigationController: UINavigationController, context: UIViewControllerRepresentableContext<SearchViewController>) {
        //
    }
}

这有效,并在用户搜索时显示searchResultsController。但是,searchResultsController 似乎不知道它是导航上下文/堆栈,因此我无法从searchResultsController 中的列表视图导航。

是否可以将其结构化为允许从 searchResultsController 导航,或者这是当前 SwiftUI 的限制。

非常感谢任何建议!

【问题讨论】:

    标签: swift swiftui ios13 uisearchcontroller


    【解决方案1】:

    我最近还需要在我的应用程序中实现此功能(搜索栏如导航栏)。看着你 sn-ps 真的启发了 m2! 首先感谢您!

    在向ula1990Lorenzo BoaroV8tr学习之后,我实现了自己的。

    我将searchResultsController 设置为nil(由于其中的导航链接不可点击,所以我将其设置为nil)。

    Demo

    代码:

    struct SearchController<Result: View>: UIViewControllerRepresentable {
        @Binding var searchText: String
        private var content: (_ searchText:String)->Result
        
        private var searchBarPlaceholder: String
        
    
        init(_ searchBarPlaceholder: String = "", searchedText: Binding<String>,
             resultView: @escaping (_ searchText:String) -> Result) {
            self.content = resultView
            self._searchText = searchedText
            self.searchBarPlaceholder = searchBarPlaceholder
        }
        func makeUIViewController(context: Context) -> UINavigationController {
            let contentViewController = UIHostingController(rootView: SearchResultView(result: $searchText, content: content))
            let navigationController = UINavigationController(rootViewController: contentViewController)
            
            let searchController = UISearchController(searchResultsController: nil)
            searchController.searchResultsUpdater = context.coordinator
            searchController.obscuresBackgroundDuringPresentation = false // for results
            searchController.searchBar.placeholder = searchBarPlaceholder
            
            contentViewController.title = "\\(Title)" // for customization
            contentViewController.navigationItem.searchController = searchController
            contentViewController.navigationItem.hidesSearchBarWhenScrolling = true
            contentViewController.definesPresentationContext = true
            
            searchController.searchBar.delegate = context.coordinator
            
            return navigationController
        }
        
        func updateUIViewController(_ uiViewController: UINavigationController, context: UIViewControllerRepresentableContext<SearchController>) {
            // 
            
        }
    }
    extension SearchController {
        func makeCoordinator() -> SearchController<Result>.Coordinator {
            Coordinator(self)
        }
        class Coordinator: NSObject, UISearchResultsUpdating, UISearchBarDelegate {
            var parent: SearchController
            init(_ parent: SearchController){self.parent = parent}
            
            // MARK: - UISearchResultsUpdating
            func updateSearchResults(for searchController: UISearchController) {
                self.parent.searchText = searchController.searchBar.text!
            }
            
            // MARK: - UISearchBarDelegate
            func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
                self.parent.searchText = ""
            }
    
            func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
                self.parent.searchText = ""
                return true
            }
        }
    }
    
    // "nofity" the result content about the searchText
    struct SearchResultView<Content: View>: View { 
        @Binding var searchText: String
        private var content: (_ searchText:String)->Content
        init(result searchText: Binding<String>, @ViewBuilder content: @escaping (_ searchText:String) -> Content) {
            self._searchText = searchText
            self.content = content
        }
        var body: some View {
            content(searchText)
        }
    }
    
    

    如果这是您想要的,我不知道,但再次感谢!

    【讨论】:

    • 您能提供一个使用示例吗?谢谢
    • @nmdias 对于上面显示的演示:检查 sn-ps here。它可能有问题,但你会明白的。
    • @EthanMengoreo sn-p 不见了:(
    【解决方案2】:

    (编辑)iOS 15:

    iOS 15 添加了新属性.searchable()。您可能应该改用它。

    原文:

    我刚刚制作了a package,它可能会解决这个问题。它类似于@EthanMengoreo 的答案,但(在我看来)具有更类似于 SwiftUI 的语法。

    我还在这里为那些不喜欢链接或只想复制/粘贴的人提供完整的相关源代码。

    扩展名:

    // Copyright © 2020 thislooksfun
    // Permission is hereby granted, free of charge, to any person obtaining a copy
    // of this software and associated documentation files (the “Software”), to deal
    // in the Software without restriction, including without limitation the rights
    // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    // copies of the Software, and to permit persons to whom the Software is
    // furnished to do so, subject to the following conditions:
    //
    // The above copyright notice and this permission notice shall be included in
    // all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    // SOFTWARE.
    
    import SwiftUI
    import Combine
    
    public extension View {
        public func navigationBarSearch(_ searchText: Binding<String>) -> some View {
            return overlay(SearchBar(text: searchText).frame(width: 0, height: 0))
        }
    }
    
    fileprivate struct SearchBar: UIViewControllerRepresentable {
        @Binding
        var text: String
        
        init(text: Binding<String>) {
            self._text = text
        }
        
        func makeUIViewController(context: Context) -> SearchBarWrapperController {
            return SearchBarWrapperController()
        }
        
        func updateUIViewController(_ controller: SearchBarWrapperController, context: Context) {
            controller.searchController = context.coordinator.searchController
        }
        
        func makeCoordinator() -> Coordinator {
            return Coordinator(text: $text)
        }
        
        class Coordinator: NSObject, UISearchResultsUpdating {
            @Binding
            var text: String
            let searchController: UISearchController
            
            private var subscription: AnyCancellable?
            
            init(text: Binding<String>) {
                self._text = text
                self.searchController = UISearchController(searchResultsController: nil)
                
                super.init()
                
                searchController.searchResultsUpdater = self
                searchController.hidesNavigationBarDuringPresentation = true
                searchController.obscuresBackgroundDuringPresentation = false
                
                self.searchController.searchBar.text = self.text
                self.subscription = self.text.publisher.sink { _ in
                    self.searchController.searchBar.text = self.text
                }
            }
            
            deinit {
                self.subscription?.cancel()
            }
            
            func updateSearchResults(for searchController: UISearchController) {
                guard let text = searchController.searchBar.text else { return }
                self.text = text
            }
        }
        
        class SearchBarWrapperController: UIViewController {
            var searchController: UISearchController? {
                didSet {
                    self.parent?.navigationItem.searchController = searchController
                }
            }
            
            override func viewWillAppear(_ animated: Bool) {
                self.parent?.navigationItem.searchController = searchController
            }
            override func viewDidAppear(_ animated: Bool) {
                self.parent?.navigationItem.searchController = searchController
            }
        }
    }
    

    用法:

    import SwiftlySearch
    
    struct MRE: View {
      let items: [String]
    
      @State
      var searchText = ""
    
      var body: some View {
        NavigationView {
          List(items.filter { $0.localizedStandardContains(searchText) }) { item in
            Text(item)
          }.navigationBarSearch(self.$searchText)
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-22
      • 2018-03-17
      • 2021-07-11
      相关资源
      最近更新 更多