第 37 章
利用 Searchable 建立搜尋欄

在 iOS 15 之前,SwiftUI 沒有內置修飾器在List視圖中加入搜尋功能。開發者必須建立自己的解決方案。 在前面的章節中,我已經介紹了兩個自建搜尋欄的方法。隨著 iOS 15 推出,SwiftUI 框架為 List 視圖帶來了一個名為 searchable 的新修飾器,讓你更輕易建立搜尋欄。

在本章中,你將學習使用searchable,待會你就會受到這個修飾器有多方便。

Searchable 的基本用法

為了講解 Searchable 的用法,請從以下網址下載範例項目:https://www.appcoda.com/resources/swiftui4/SwiftUISearchableStarter.zip.

圖 37.1. 範例項目
圖 37.1. 範例項目

範例的初始項目已經準備好了一個列表視圖來顯示一組文章。 之後,我們會加入一個用於過濾文章的搜尋欄。 要將搜尋欄添加到列表視圖,你需要做的就是宣告一個狀態變數(例如searchText)來存放搜尋文字並將searchable修飾器附加到NavigationStack,如下所示:

struct ContentView: View {

    @State var articles = sampleArticles
    @State private var searchText = ""

    var body: some View {
        NavigationStack {
            .
            .
            .
        }
        .searchable(text: $searchText)
    }
}

SwiftUI 會自動為你加入搜尋欄,並將其放在導航欄標題下方。 如果找不到搜尋欄,請嘗試執行App並向下拖動列表視圖。 這樣搜尋框就應該出現。

圖 37.2. searchable 修飾器自動為你加入搜尋欄
圖 37.2. searchable 修飾器自動為你加入搜尋欄

在預設情況下,它顯示 Search 作為佔位符。 如果你想更改它,你可以像這樣編寫.searchable修飾器並使用你指定的佔位符:

.searchable(text: $searchText, prompt: "Search articles...")

搜尋欄位置

.searchable 修飾器有一個 placement 參數,用於指定搜尋欄的位置。 在預設的情況下,它設置為.automatic。 就 iPhone 而言,搜尋欄會顯示於導航欄標題下方。 當你向上滾動列表視圖時,搜尋欄就會自動隱藏。

如果想永久顯示搜尋欄,可以更改 .searchable 修飾器並提供 placement 參數,如下所示:

.searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always))

到目前為止,我們將 .searchable 修飾器附加到導航視圖。 你實際上可以將它附加到 List 視圖並在 iPhone 上實現相同的結果。

話雖如此,在 iPadOS 上使用 split view 時,.searchable 修飾器的擺放位置會直接影響搜尋欄的顯示位置。 再看一下範例程式碼:

NavigationSplitView {
    List {
        ForEach(articles) { article in
            ArticleRow(article: article)
        }

        .listRowSeparator(.hidden)

    }
    .listStyle(.plain)

    .navigationTitle("AppCoda")
} detail: {
    Text("Article details")
}
.searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always))

像往常一樣,我們將 .searchable 修飾器附加到導航視圖。 如果你在 iPad 上運行範例App,搜尋欄會顯示在拆分視圖的側邊欄上。

圖 37.3. 在 iPad 上顯示拆分視圖的搜索欄
圖 37.3. 在 iPad 上顯示拆分視圖的搜索欄

如果你想將搜尋欄放在詳細視圖中,那應怎樣做? 你可以嘗試在 .navigationTitle 修飾器的正上方加入以下程式碼:

Text("Article details")
    .searchable(text: $searchText)

這樣,iPadOS 將在詳細視圖的右上角顯示一個額外的搜尋欄。

圖 37.4. 在詳細視圖的右上角顯示一個額外的搜尋欄
圖 37.4. 在詳細視圖的右上角顯示一個額外的搜尋欄

同樣地,你可以通過調整 placement 參數的值來進一步更改搜尋欄的位置。 這是一個例子:

.searchable(text: $searchText, placement: .navigationBarDrawer)

通過將 placement 參數設置為 .navigationBarDrawer,iPadOS 就會將搜尋欄置於導航欄標題下方。

圖 37.5. 利用 .navigationBarDrawer 改變搜尋欄位置
圖 37.5. 利用 .navigationBarDrawer 改變搜尋欄位置

如何執行搜尋並顯示搜索結果

搜尋數據的方法有很多種。 你可以建立一個計算屬性(computed property)來實時過濾數據。 又或者,你可以附加 .onChange 修飾器以監測使用者輸入的搜尋文字,如有更改就立刻啟動搜尋。 試試更新 NavigationStack 的程式碼,如下所示:

NavigationStack {
    List {
        ForEach(articles) { article in
            ArticleRow(article: article)
        }

        .listRowSeparator(.hidden)

    }
    .listStyle(.plain)

    .navigationTitle("AppCoda")
}
.searchable(text: $searchText)
.onChange(of: searchText) { searchText in

    if !searchText.isEmpty {
        articles = sampleArticles.filter { $0.title.contains(searchText) }
    } else {
        articles = sampleArticles
    }
}

每當使用者輸入搜尋字時,App都會執行 .onChange 修飾器。 然後我們使用 filter 方法實時進行搜尋。Xcode 預覽無法正常搜索,請在模擬器上測試搜索功能。

圖 37.6. 執行搜尋
圖 37.6. 執行搜尋

添加搜尋建議

.searchable 修飾器允許你添加搜尋建議列表,以顯示一些常用的搜索詞或搜尋歷史。 例如,你可以像這樣建立可點擊的搜尋建議:

.searchable(text: $searchText) {
    Text("SwiftUI").searchCompletion("SwiftUI")
    Text("iOS 15").searchCompletion("iOS 15")
}

當使用者進行搜索時,搜尋欄就會顯示兩個常用的搜尋建議。 使用者可以鍵入搜尋關鍵字或點擊搜尋建議來執行搜索。

圖 37.7. 顯示搜尋建議
圖 37.7. 顯示搜尋建議

在 iOS 16 上,Apple 引入了一個名為 .searchSuggestions 的修飾符,用於添加搜索建議。 以上同一段程式碼可以寫成這樣:

.searchable(text: $searchText)
.searchSuggestions {
    Text("SwiftUI").searchCompletion("SwiftUI")
    Text("iOS 15").searchCompletion("iOS 15")
}

總結

.searchable 修飾器簡化了搜尋欄的實作方法。在一般情況下,我們不再需要自己開發搜尋欄。 缺點是此功能僅適用於 iOS 15(或更高版本)。 如果你正在構建一個需要支持舊版本 iOS 的應用程序,你仍然需要建立自己的搜尋欄。


想更深入學習SwiftUI和下載完整程式碼?你可以從 AppCoda網站購買《精通 SwiftUI》完整電子版。

results matching ""

    No results matching ""