swift uiで検索プルダウンを作成


イメージはこんな感じ
![スクリーンショット 2024-01-19 15.56.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/bb8182c4-1791-df48-c1fc-63a1bd5f02a1.png)

    import SwiftUI
    
    // 新しいデータ型
    struct YourNewDataType: Identifiable {
        var id: UUID
        var name: String
        // 他のプロパティや初期化処理を必要に応じて追加
    }
    
    // サンプルデータ
    let yourNewDataArray: [YourNewDataType] = [
        YourNewDataType(id: UUID(), name: "Item 1"),
        YourNewDataType(id: UUID(), name: "Item 2"),
        // 他のデータを追加
    ]
    
    struct ContentView: View {
        @State private var searchText = ""
        @State private var isPopupPresented = false
        @State private var selectedData: YourNewDataType?
    
        var body: some View {
            ZStack {
                TextField("", text: $searchText)
                    .frame(width: 370, height: 42, alignment: .leading)
                    .padding(.leading, 10)
                    .border(Color.gray, width: 1)
                    .padding(.bottom, 30)
                    .onTapGesture {
                        UIApplication.shared.sendAction(#selector(UIResponder.becomeFirstResponder), to: nil, from: nil, for: nil)
                        isPopupPresented = true
                    }
                    .overlay(
                        isPopupPresented ?
                        VStack() {
                            if searchText.isEmpty {
                                VStack(spacing: 0) {
                                    siteScrollView(data: yourNewDataArray)
                                }
                            } else {
                                VStack(spacing: 0) {
                                    filteredSiteScrollView(data: yourNewDataArray)
                                }
                            }
                        }
                        .frame(width: 380, alignment: .leading)
                        .border(Color.gray, width: 1)
                        : nil
                    )
            }
        }
    
        // siteScrollView 関数の修正
        func siteScrollView(data: [YourNewDataType]) -> some View {
            return ScrollView {
                VStack(spacing: 0) {
                    ForEach(data) { item in
                        VStack(spacing: 0) {
                            Text(item.name)
                                .onTapGesture {
                                    self.selectedData = item
                                    isPopupPresented = false
                                    searchText = item.name
                                }
                                .frame(width: 370, alignment: .leading)
                                .padding(10)
    
                            Rectangle()
                                .frame(height: 1)
                                .foregroundColor(Color.gray)
                                .frame(width: 370, alignment: .leading)
                        }
                    }
                }
            }
            .background(Color.gray) // 仮の色設定
            .frame(height: 160)
        }
    
        // filteredSiteScrollView 関数の修正
        func filteredSiteScrollView(data: [YourNewDataType]) -> some View {
            let filteredData = data.filter { $0.name.localizedCaseInsensitiveContains(searchText) }
    
            return ScrollView {
                VStack(spacing: 0) {
                    ForEach(filteredData) { item in
                        VStack(spacing: 0) {
                            Text(item.name)
                                .onTapGesture {
                                    self.selectedData = item
                                    isPopupPresented = false
                                    UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
                                    searchText = item.name
                                }
                                .frame(width: 370, alignment: .leading)
                                .padding(10)
    
                            if filteredData.count > 1 {
                                Rectangle()
                                    .frame(height: 1)
                                    .foregroundColor(Color.gray)
                                    .frame(width: 370, alignment: .leading)
                            }
                        }
                    }
                }
            }
            .frame(height: filteredData.count > 1 ? 80 : 40)
            .background(Color.gray) // 仮の色設定
        }
    }

iPadではsheetやpopoverとTextField+MENUの組み合わせでなんとか検索プルダウン的なのはできたんですが、iPhoneで横画面の場合全画面表示になってしまいそちらでは対応できず、パッケージなどもなかったので仕方なく独自で作成しました

## できたこと

横並びにしたい場合HStackでテキストとテキストフィールド部分囲えばできます
テキストフィールドをクリアしたいなどの場合はオーバーレイをもう一つ追加してそこでボタンやイメージなどを追加すれば可能です（offsetなどで場所を操作する必要はある）

## まとめ

Webでよく使われる検索プルダウンがiosでは存在しなくてどうしようかなってずっと悩みながらトライしてたんですが、結局色々探したけどできなかったし、記事も見つからなかったので自作するしかないかって諦めて久々に頭を使いました

多分Webと同じにしたいとかそんな理由でiosでも検索プルダウンを実装してくれみたいなことを言われる方はこれからもいるだろうな

また自分も言われるだろうし、記事もなかったので自身の忘備録を兼ねて投稿です

どなたかの参考になれば幸いです。ではまた