【问题标题】:Adding a search bar to NavigationView in SwiftUI在 SwiftUI 中向 NavigationView 添加搜索栏
【发布时间】:2020-01-13 03:07:29
【问题描述】:

我正在使用 SwiftUI 创建一个项目,并希望在导航栏中添加一个搜索栏,就像原生设置应用程序、邮件应用程序等中存在的那样。

我尝试了一些方法,但无法完全发挥作用。以下代码运行良好,但即使包含navigationController.navigationItem.hidesSearchBarWhenScrolling = false,搜索栏也不会显示(我尝试向上滚动)。任何帮助将不胜感激。

//
//  ContentView.swift
//  SwiftUITest
//
//  Created by me on 1/7/20.
//  Copyright © 2020 me. All rights reserved.
//

import SwiftUI

struct HomeView: View {
    var body: some View {
        ScrollView {
            HStack {
                Spacer(minLength: 0)

                Text("Hello World")

                Spacer(minLength: 0)
            }
        }
        .navigationBarTitle(Text("Search"))
    }
}

struct SecondView: View {
    var body: some View {
        return Text("Second View")
    }
}

struct CustomUIViewControllerRepresentation: UIViewControllerRepresentable {
    typealias UIViewControllerType = UINavigationController

    func makeUIViewController(context: Context) -> UINavigationController {
        let viewController = UIHostingController(rootView: HomeView())

        let navigationController = UINavigationController(rootViewController: viewController)
        navigationController.navigationBar.prefersLargeTitles = true

        let searchController = UISearchController()
        navigationController.navigationItem.searchController = searchController

        return navigationController
    }

    func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {

    }
}


struct ContentView: View {
    var body: some View {
        CustomUIViewControllerRepresentation()
    }
}

【问题讨论】:

    标签: swift uikit swiftui


    【解决方案1】:

    (编辑)iOS 15:

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

    原文:

    如果有人还在寻找,我发了a package 来解决这个问题,因为我找到的所有其他解决方案都有一些问题。

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

    扩展名:

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

    【讨论】:

      【解决方案2】:

      试试这个:

      -> 缺少这一行:viewController.navigationItem.searchController = searchController

       func makeUIViewController(context: Context) -> UINavigationController {
              let viewController = UIHostingController(rootView: HomeView())
      
              let navigationController = UINavigationController(rootViewController: viewController)
              navigationController.navigationBar.prefersLargeTitles = true
      
              let searchController = UISearchController()
              navigationController.navigationItem.searchController = searchController
      
      
              viewController.navigationItem.searchController = searchController
      
              return navigationController
          }
      

      【讨论】:

      • @RedaLemeden 当您从搜索者读取值时,您可以分享完整的解决方案吗?
      • @PawełMadej 从那以后我放弃了这个解决方案。我发现了其他我现在不记得的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-25
      • 1970-01-01
      • 2022-01-04
      • 1970-01-01
      相关资源
      最近更新 更多