【问题标题】:SwiftUI - Search in List HeaderSwiftUI - 在列表标题中搜索
【发布时间】:2019-10-29 17:31:27
【问题描述】:

我正在尝试使用 SwiftUI 重新创建每个人都知道的 UITableView 中的内容:tableview 标题中的一个简单搜索字段:

然而,SwiftUI 中的列表视图似乎甚至没有办法添加页眉或页脚。您可以将带有 TextField 的标题设置为如下部分:

@State private var searchQuery: String = ""

var body: some View {

List {
    Section(header:
        Group{
            TextField($searchQuery, placeholder: Text("Search"))
                                .background(Color.white)
            }) {
                  ListCell()
                  ListCell()
                  ListCell()
                }

    }
}

但是,我不确定这是否是最好的方法,因为:

  1. 从 UITableView 向下滚动时,标题不会隐藏。
  2. SearchField 看起来不像我们熟悉和喜爱的搜索字段。

有没有人找到好的方法?我不想依赖 UITableView。

【问题讨论】:

    标签: uitableview search textfield swiftui


    【解决方案1】:

    Xcode 13 / SwiftUI 3

    您现在可以使用.searchable 使列表...可搜索!

    struct ContentView: View {
    
        @State private var searchQuery: String = ""
    
        var body: some View {
            NavigationView {
                List {
                    ForEach(Array(1...100)
                                .map { "\($0)" }
                                .filter { searchQuery.isEmpty ? true : $0.contains(searchQuery) }
                            ,id: \.self) { item in
                        Text(verbatim: item)
                    }
                }
                .navigationTitle("Fancy Numbers")
                .searchable(text: $searchQuery)
            }
        }
    
    }
    

    搜索栏似乎只有在 List 嵌入到 NavigationView 时才会出现。


    Xcode 12,SwiftUI 1/2

    您可以将UISearchBar 移植到 SwiftUI。

    (有关此内容的更多信息,请参阅出色的 WWDC 2019 演讲 - Integrating SwiftUI

    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() -> Coordinator {
            return Coordinator(text: $text)
        }
    
        func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
            let searchBar = UISearchBar(frame: .zero)
            searchBar.delegate = context.coordinator
            return searchBar
        }
    
        func updateUIView(_ uiView: UISearchBar,
                          context: UIViewRepresentableContext<SearchBar>) {
            uiView.text = text
        }
    }
    

    并像这样使用它:

    struct ContentView: View {
    
        @State private var searchQuery: String = ""
    
        var body: some View {
    
            List {
                Section(header: SearchBar(text: self.$searchQuery)) {
                    ForEach(Array(1...100).filter {
                        self.searchQuery.isEmpty ?
                            true :
                            "\($0)".contains(self.searchQuery)
                    }, id: \.self) { item in
                        Text("\(item)")
                    }
                }
            }
        }
    }
    

    这是正确的搜索栏,但它不会隐藏 - 我相信我们将能够在某个时候通过 SwiftUI API 做到这一点。

    看起来像这样

    【讨论】:

    • 谢谢,在这里使用 UISearchBar 可能是最好的主意。
    • @Daniel 直到 SwiftUI 变得更好:)
    • 是的,我确信 Apple 在未来对 SwiftUI 有很多计划。
    • 这让我的编译器崩溃(在 Mojave 的 Playground 中尝试过,可能与此有关?)。
    • 不放在表头可以更好看。相反,将它放在一个间距为 0 且包含搜索栏和列表的 VStack 中:VStack(alignment: .center, spacing: 0) { SearchBar(text: self.$searchQuery); List { ...。这样您就可以使用全宽,并且搜索栏始终保持在顶部。
    【解决方案2】:

    也许这里是一个起点。考虑使用ZStack 来实现scrollview 的滚动消失效果。

    
    struct ContentView: View {
        @State var search: String
    
        var body: some View {
            NavigationView {
                VStack(alignment: .center, spacing: 0) {
                    HStack {
                        Image(systemName: "magnifyingglass")
                            .padding(.leading, CGFloat(10.0))
                        TextField("Search", text: $search, onEditingChanged: { active in
                            print("Editing changed: \(active)")
                        }, onCommit: {
                            print("Commited: \(self.search)")
                        })
                            .padding(.vertical, CGFloat(4.0))
                            .padding(.trailing, CGFloat(10.0))
                    }
                        .overlay(
                            RoundedRectangle(cornerRadius: 5.0)
                                .stroke(Color.secondary, lineWidth: 1.0)
                        )
                        .padding()
                    List {
                        ForEach(0...100, id: \.self) { e in
                            Text("Item \(e)")
                        }
                    }
                }
                .navigationBarTitle(title(for: self.search))
            }
        }
    
        private func title(for value: String?) -> String {
            guard let value = value, value.count > 0 else {
                return "No search"
            }
    
            return #"Searching for "\#(value)""#
        }
    }
    
    

    【讨论】:

    • 嘿,如何为search 的每次更改触发一个动作(例如调用一个函数)会很有趣。这可能吗?
    • @blackjacx 我正在寻找相同的解决方案。你有吗?
    • @blackjacx 只需附加解决方案即可。
    • @FlorentMorin 我一定遗漏了什么,但我在你的代码中没有看到ZStack
    【解决方案3】:

    我使用 SwiftUI 实现了我的国家/地区选择器项目Columbus。我实现了一个自定义发布者CountryListViewModel 并将其与文本字段连接起来。通过这种方式,我可以键入、搜索数据源、过滤结果/去抖动并在所有操作完成后更新表格视图。效果不错?

    https://github.com/Blackjacx/Columbus/tree/swift-ui/Source/Classes

    【讨论】:

      【解决方案4】:

      2021 — Xcode 13 / SwiftUI 3

      原生 SwiftUI 解决方案:

      List {
          ForEach(0..<5) {
              index in
                  Text("item \(index)")
              }
          }
      }
      .searchable(text: .constant("search_value")) // should be a Binding
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-30
        相关资源
        最近更新 更多