1. ホーム
  2. swiftui

SwiftUIで検索バーを表示する方法

2023-10-12 08:48:59

質問

新しいSwiftUIフレームワークは組み込みの検索バーコンポーネントを提供しないようです。UISearchControllerを使い、何らかの方法でラップするべきか、あるいは単純なテキストフィールドを使い、テキストフィールドの入力に従ってデータを更新すべきでしょうか?

EDIT: 現在のところ、回避策として TextField をsearchBarとして使用することです。これは非常にうまくいっていますが、検索アイコンがありません。

import SwiftUI

struct Search : View {
  
  let array = ["John","Lena","Steve","Chris","Catalina"]
  
  @State private var searchText = ""
  
  var body: some View {
      NavigationView{
        List{
            TextField("Type your search",text: $searchText)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            
            ForEach(array.filter{$0.hasPrefix(searchText) || searchText == ""}, id:\.self){searchText in
                Text(searchText)
            }
        }
        .navigationBarTitle(Text("Search"))
      }
  }
}

struct Search_Previews : PreviewProvider {
  static var previews: some View {
    Search()
  }
}

Xcode 11.1 で動作するように更新しました。

どのように解決するのですか?

以下は、純粋なswiftUIバージョンで、ベースは Antoine Weber の の質問に対する回答と、私が見つけた このブログ この要旨 . を組み込んでいます。

  • クリアボタン。
  • キャンセルボタン
  • リスト内のドラッグでキーボードを放棄し
  • 検索テキスト フィールドが選択されると、ナビゲーション ビューを非表示にする。

リスト内でドラッグした際にキーボードを放棄することは、以下のUIApplicationウィンドウのメソッドを使用して実現することができます。 これらの回答 . より簡単に処理するために、私はUIApplicationの拡張機能とこの拡張機能のためのビューモディファイアを作成し、最終的にビューの拡張機能を作成しました。

extension UIApplication {
    func endEditing(_ force: Bool) {
        self.windows
            .filter{$0.isKeyWindow}
            .first?
            .endEditing(force)
    }
}

struct ResignKeyboardOnDragGesture: ViewModifier {
    var gesture = DragGesture().onChanged{_ in
        UIApplication.shared.endEditing(true)
    }
    func body(content: Content) -> some View {
        content.gesture(gesture)
    }
}

extension View {
    func resignKeyboardOnDragGesture() -> some View {
        return modifier(ResignKeyboardOnDragGesture())
    }
}

つまり、キーボードを辞任するための最終的なモディファイアは、このようにリストに載せるだけでいいのです。

List {
    ForEach(...) {
        //...
    }
}
.resignKeyboardOnDragGesture()

検索バーの完全なswiftUIプロジェクトコードと、名前のリストのサンプルは次のとおりです。新しいswiftUIプロジェクトのContentView.swiftに貼り付けて遊べます。


import SwiftUI

struct ContentView: View {
    let array = ["Peter", "Paul", "Mary", "Anna-Lena", "George", "John", "Greg", "Thomas", "Robert", "Bernie", "Mike", "Benno", "Hugo", "Miles", "Michael", "Mikel", "Tim", "Tom", "Lottie", "Lorrie", "Barbara"]
    @State private var searchText = ""
    @State private var showCancelButton: Bool = false

    var body: some View {

        NavigationView {
            VStack {
                // Search view
                HStack {
                    HStack {
                        Image(systemName: "magnifyingglass")

                        TextField("search", text: $searchText, onEditingChanged: { isEditing in
                            self.showCancelButton = true
                        }, onCommit: {
                            print("onCommit")
                        }).foregroundColor(.primary)

                        Button(action: {
                            self.searchText = ""
                        }) {
                            Image(systemName: "xmark.circle.fill").opacity(searchText == "" ? 0 : 1)
                        }
                    }
                    .padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
                    .foregroundColor(.secondary)
                    .background(Color(.secondarySystemBackground))
                    .cornerRadius(10.0)

                    if showCancelButton  {
                        Button("Cancel") {
                                UIApplication.shared.endEditing(true) // this must be placed before the other commands here
                                self.searchText = ""
                                self.showCancelButton = false
                        }
                        .foregroundColor(Color(.systemBlue))
                    }
                }
                .padding(.horizontal)
                .navigationBarHidden(showCancelButton) // .animation(.default) // animation does not work properly

                List {
                    // Filtered list of names
                    ForEach(array.filter{$0.hasPrefix(searchText) || searchText == ""}, id:\.self) {
                        searchText in Text(searchText)
                    }
                }
                .navigationBarTitle(Text("Search"))
                .resignKeyboardOnDragGesture()
            }
        }
    }
}



struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
           ContentView()
              .environment(\.colorScheme, .light)

           ContentView()
              .environment(\.colorScheme, .dark)
        }
    }
}

extension UIApplication {
    func endEditing(_ force: Bool) {
        self.windows
            .filter{$0.isKeyWindow}
            .first?
            .endEditing(force)
    }
}

struct ResignKeyboardOnDragGesture: ViewModifier {
    var gesture = DragGesture().onChanged{_ in
        UIApplication.shared.endEditing(true)
    }
    func body(content: Content) -> some View {
        content.gesture(gesture)
    }
}

extension View {
    func resignKeyboardOnDragGesture() -> some View {
        return modifier(ResignKeyboardOnDragGesture())
    }
}

検索バーの最終結果は、初期状態では次のように表示されます。

で、検索バーをこのように編集した場合。

動作中です。