SwiftUIアプリに検索機能を追加して、検索候補を提供（.searchable）（iOS 15）

こちらはSwiftUIアプリに検索機能の追加して、ユーザーの入力に基づいた検索候補の提供を行うことに関する短い記事です。

![search-5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/9d3e3f73-fc20-7444-8517-551224a1a8c4.jpeg)

検索候補機能は、iOS 15でしか利用できない可能性があります。

## 出発点

まずは、猫についての情報のリストを含むSwiftUIビューから始めましょう。

```swift
//
//  ContentView.swift
//  Demo
//
//  Created by Shunzhe on 2021/12/31.
//

import SwiftUI

struct ContentView: View {
    
    @State private var searchText: String = ""
    
    let catInfos: [CatInfo] = [
        .init(catName: "ムギ", catColor: .orange, catDescription: "This is an orange cat who likes to eat a lot of fish."),
        .init(catName: "ソラ", catColor: .orange, catDescription: "This is an orange cat who likes to play with the cat house."),
        .init(catName: "ココ", catColor: .black, catDescription: "This is a kuro neko who likes to sleep near the office desk.")
    ]
    
    var body: some View {
        
        NavigationView {
            
            List(catInfos) { catInfo in
                VStack(alignment: .leading) {
                    Text(catInfo.catName)
                        .font(.headline)
                        .foregroundColor(catInfo.catColor)
                    Text(catInfo.catDescription)
                }
            }
            .navigationTitle("Cats List")
        
    }
    
}

struct CatInfo: Identifiable {
    var id: String {
        return catName
    }
    var catName: String
    var catColor: Color
    var catDescription: String
}

```

## 検索機能の追加

### 最初に、ユーザーが入力したテキストを格納する変数を定義

```swift
@State private var searchText: String = ""
```

そうしたら、`.searchable` ビューモディファイアを `List` リストビュー要素に追加します。

```swift
.searchable(text: $searchText, placement: .navigationBarDrawer, prompt: "Search from cat names")
```

次に、ユーザーが入力した検索テキストを使って、リストの内容を更新します。

```swift
List(catInfos.filter({ catInfo in
    if self.searchText.isEmpty {
        return true
    }
    return catInfo.catName == self.searchText
})) { catInfo in
    VStack(alignment: .leading) {
        Text(catInfo.catName)
            .font(.headline)
            .foregroundColor(catInfo.catColor)
        Text(catInfo.catDescription)
    }
}
```

ここでは、指定された条件に基づいてリストのアイテムがフィルタリングされます。検索テキストが空の場合はフィルタは適用されず、空でない場合は入力された検索テキストが猫の名前と一致するかチェックされます。

これで、猫の名前を検索できるようになったはずです。

![ezgif-5-929ab37a52.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/38ade08c-358d-95d0-2725-3de1c31669f1.gif)

**猫を探すのに名前すべてを入力しなくてはならないという問題が発生しています。検索候補を表示することによって、この問題を解決する必要があります。**

## 検索候補を表示

ユーザーが検索文字列を入力する際に候補を表示できます

`.searchable`のコーディングブロックを追加するだけで、この機能を追加できます。

```swift
    .searchable(text: $searchText, placement: .navigationBarDrawer, prompt: "Search from cat names")
{
    // Search suggestions generation logic
    let matchedItems = self.catInfos.filter({ catInfo in
        return catInfo.catName.contains(self.searchText)
    })
    // UI
    if matchedItems.isEmpty {
        Text("No suggestions found.")
    }
    ForEach(matchedItems) { catInfo in
        Text("Are you looking for \(catInfo.catName)?")
            .searchCompletion(catInfo.catName)
    }
}
```

このコードブロック内に検索候補を生成します。このデモでは、入力された検索テキストが猫の名前に含まれているかどうかをチェックするだけです。またアプリ内で、データベースへの問い合わせやAPI呼び出しを使ってこの結果を生成することもできます。

`Text`テキストコンポーネントを使用して候補を表示し、ユーザーがクリックして検索候補の1つを適用できるように`.searchCompletion`修飾子が使用されます。

![ezgif-5-fe1744e5b0.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/8d4edbd2-e8c5-3c56-6eba-0b557568055a.gif)

## 完成したコード

https://gist.github.com/mszpro/e22105fa05485b2e8025e9cb2a8eaa25