如何使用SwiftUI显示搜索栏

时间:2019-06-07 08:47:30

标签: swiftui

新的SwiftUI框架似乎未提供内置的搜索栏组件。应该使用UISearchController并以某种方式包装它,还是应该使用简单的文本字段并根据文本字段输入更新数据?

编辑:当前解决方法是将文本字段用作searchBar。它运行良好,但没有搜索图标

    import SwiftUI

    struct Search : View {

      let array = ["John","Lena","Steve","Chris","Catalina"]

      @State private var searchText = ""

      var body: some View {


        NavigationView{
          List(){
            TextField($searchText)
              .textFieldStyle(.roundedBorder)

            ForEach(array.filter{$0.hasPrefix(searchText) || searchText == "" }.identified(by: \.self)){
              Text($0)
            }
            }
            .navigationBarTitle(Text("Search"))
        }


      }
    }

    #if DEBUG
    struct Search_Previews : PreviewProvider {
      static var previews: some View {
        Search()
      }
    }
    #endif

6 个答案:

答案 0 :(得分:25)

这里是纯swiftUI版本,基于Antoine Weber's对上述问题的解答以及我在this blogthis gist中发现的内容。它包含

  • 清除按钮,
  • 取消按钮,
  • 在拖动列表时退出键盘,
  • 在选择搜索文本字段时隐藏导航视图。

使用these answers之后的UIApplication窗口上的方法,可以在拖动列表中退出键盘。为了便于处理,我在UIApplication上创建了一个扩展,并为此扩展了view修饰符,最后为View创建了一个扩展:

Car

因此,退出键盘的最后一个修饰符只是一个必须像这样放置在列表中的修饰符:

user_id

带有名称示例列表的搜索栏的完整swiftUI项目代码如下。您可以将其粘贴到新的swiftUI项目的ContentView.swift中并进行播放。

current_user.id

搜索栏的最终结果在最初显示时是这样的

enter image description here

,然后按以下方式编辑搜索栏:

enter image description here

实际操作:

enter image description here

答案 1 :(得分:8)

此YouTube video展示了如何完成此操作。归结为:

for (int arrayChecker = 0; arrayChecker < originList.size(); arrayChecker++) {
    if (originList.get(arrayChecker).toString().equals(firstEle.getText())
            && destinationList.get(arrayChecker).toString().equals(lastEle.getText())) {
        totalPeople += Integer.parseInt(peopleList.get(arrayChecker).toString());
    }
}
numberAsString = numberFormat.format(totalPeople);
assertEquals(infoElement.getText(), "Information: Total time: " + numberAsString + " people");

,然后代替

struct SearchBar: 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
        }
    }
    func makeCoordinator() -> SearchBar.Coordinator {
        return Coordinator(text: $text)
    }

    func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator
        searchBar.autocapitalizationType = .none
        return searchBar
    }

    func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext<SearchBar>) {
        uiView.text = text
    }
}

您使用

TextField($searchText)
              .textFieldStyle(.roundedBorder)

答案 2 :(得分:7)

通过包装UINavigationController,可以在SwiftUI中正确实现本机搜索栏。

这种方法为我们提供了实现所有预期行为的优势,包括自动滚动显示/隐藏,清除和取消按钮以及键盘中的搜索键等。

为搜索栏包装UINavigationController还可确保您的项目中自动采用Apple对它们所做的任何新更改。

示例输出

Click here to see the implementation in action

代码(包装UINavigationController):

import SwiftUI

struct SearchNavigation<Content: View>: UIViewControllerRepresentable {
    @Binding var text: String
    var search: () -> Void
    var cancel: () -> Void
    var content: () -> Content

    func makeUIViewController(context: Context) -> UINavigationController {
        let navigationController = UINavigationController(rootViewController: context.coordinator.rootViewController)
        navigationController.navigationBar.prefersLargeTitles = true
        
        context.coordinator.searchController.searchBar.delegate = context.coordinator
        
        return navigationController
    }
    
    func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {
        context.coordinator.update(content: content())
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(content: content(), searchText: $text, searchAction: search, cancelAction: cancel)
    }
    
    class Coordinator: NSObject, UISearchBarDelegate {
        @Binding var text: String
        let rootViewController: UIHostingController<Content>
        let searchController = UISearchController(searchResultsController: nil)
        var search: () -> Void
        var cancel: () -> Void
        
        init(content: Content, searchText: Binding<String>, searchAction: @escaping () -> Void, cancelAction: @escaping () -> Void) {
            rootViewController = UIHostingController(rootView: content)
            searchController.searchBar.autocapitalizationType = .none
            searchController.obscuresBackgroundDuringPresentation = false
            rootViewController.navigationItem.searchController = searchController
            
            _text = searchText
            search = searchAction
            cancel = cancelAction
        }
        
        func update(content: Content) {
            rootViewController.rootView = content
            rootViewController.view.setNeedsDisplay()
        }
        
        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            text = searchText
        }
        
        func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
            search()
        }
        
        func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
            cancel()
        }
    }
    
}

上面的代码可以按原样使用(当然可以修改以适合项目的特定需求)。

该视图包括“搜索”和“取消”操作,当在键盘上轻按搜索键并按下搜索栏的取消按钮时,分别调用这些操作。该视图还包含一个SwiftUI视图作为结尾闭包,因此可以直接替换NavigationView。

用法(在SwiftUI视图中):

import SwiftUI

struct YourView: View {
    // Search string to use in the search bar
    @State var searchString = ""
    
    // Search action. Called when search key pressed on keyboard
    func search() {
    }
    
    // Cancel action. Called when cancel button of search bar pressed
    func cancel() {
    }
    
    // View body
    var body: some View {
        // Search Navigation. Can be used like a normal SwiftUI NavigationView.
        SearchNavigation(text: $searchString, search: search, cancel: cancel) {
            // Example SwiftUI View
            List(dataArray) { data in
                Text(data.text)
            }
            .navigationBarTitle("Usage Example")
        }
        .edgesIgnoringSafeArea(.top)
    }
}

我也为此写了一个article,可以参考它来获得进一步的说明。

我希望这会有所帮助,加油!

答案 3 :(得分:6)

iOS 15.0+

macOS 12.0+、Mac Catalyst 15.0+、tvOS 15.0+、watchOS 8.0+

<块引用>

searchable(_:text:placement:)

将此视图标记为可搜索,这将配置搜索字段的显示。 https://developer.apple.com/

struct DestinationPageView: View {
    @State private var text = ""
    var body: some View {
      NavigationView {
        PrimaryView()
        SecondaryView()
        Text("Select a primary and secondary item")
     }
     .searchable(text: $text)
  }
}

观看此 WWDC 视频了解更多信息

Craft search experiences in SwiftUI

答案 4 :(得分:1)

许多UIKit组件当前没有SwiftUI等效项。为了使用它们,您可以像在https://developer.apple.com/tutorials/swiftui/creating-and-combining-views中那样创建包装器。

基本上,您将创建一个符合UIViewRepresentable并实现makeUIView和updateUIView的SwiftUI类。

答案 5 :(得分:1)

这适用于 SwiftUI 中的 iOS 15.0+

struct SearchableList: View {
    
    let groceries = ["Apple", "Banana", "Grapes"]
    @State private var searchText: String = ""
    
    var body: some View {
        NavigationView {
            List(searchResult, id: \.self) { grocerie in
                Button("\(grocerie)") { print("Tapped") }
            }
            .searchable(text: $searchText)
        }
    }
    
    var searchResult: [String] {
        guard !searchText.isEmpty else { return groceries }
        return groceries.filter { $0.contains(searchText) }
    }
}

struct SearchableList_Previews: PreviewProvider {
    static var previews: some View {
        SearchableList().previewLayout(.sizeThatFits)
    }
}