简体   繁体   English

SwiftUI 搜索栏与导航栏一致

[英]SwiftUI Search Bar in line with navigation bar

Does anyone have working Swiftui code that will produce a search bar in the navigation bar that is inline with the back button?有没有人有有效的 Swiftui 代码可以在导航栏中生成一个与后退按钮内联的搜索栏? As if it is a toolbar item.就好像它是一个工具栏项。

Currently I have code that will produce a search bar below the navigation back button but would like it in line like the picture attached shows (where the "hi" is):目前我有代码会在导航后退按钮下方生成一个搜索栏,但希望它像所附图片显示的那样(“hi”所在的位置): 在此处输入图像描述

I am using code that I found in an example:我正在使用在示例中找到的代码:

    var body: some View {

        let shopList = genShopList(receiptList: allReceipts)

        
        VStack{
            
        }
        .navigationBarSearch(self.$searchInput)

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

If anyone has a solution to this problem that would be greatly appreciated.如果有人对此问题有解决方案,将不胜感激。 I know that in IoS 15 they are bringing out.searchable but looking for something that will work for earlier versions too.我知道在 IoS 15 中,他们正在推出 out.searchable,但正在寻找也适用于早期版本的东西。

You can put any control in the position you want by using the .toolbar modifier (iOS 14+) and an item with .principal placement, eg:您可以使用.toolbar修饰符(iOS 14+)和带有.principal放置的项目,将任何控件放入所需的 position 中,例如:

var body: some View {
  VStack {
    // rest of view
  }
  .toolbar {
    ToolbarItem(placement: .principal) {
      MySearchField(text: $searchText)
    }
  }
}

A couple of things to note:有几点需要注意:

  1. The principal position overrides an inline navigation title, either when it's set with .navigationBarTitleDisplayMode(.inline) or when you have a large title and scroll up the page.主体 position 会覆盖内联导航标题,无论是在使用.navigationBarTitleDisplayMode(.inline)设置时,还是在标题较大并向上滚动页面时。

  2. It's possible that your custom view expands horizontally so much that the back button loses any text component.您的自定义视图可能会水平扩展太多,以至于后退按钮丢失任何文本组件。 Here, I used a TextField to illustrate the point:在这里,我使用了一个TextField来说明这一点:

主要位置的搜索字段

You might be able to mitigate for that by assigning a maximum width with .frame(maxWidth:) , but at the very least it's something to be aware of.您可以通过使用.frame(maxWidth:)分配最大宽度来缓解这种情况,但至少需要注意这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM