利用 Searchable 修飾符 輕鬆在 SwiftUI List 視圖中實作搜尋欄


在 iOS 15 推出之前,SwiftUI 並沒有內置修飾符來在 List 視圖中處理搜尋,開發者需要創建自己的解決方案。我們還寫了一篇教學文章,教大家利用 TextField 來打造一個搜尋欄 (search bar),並顯示搜尋結果。在 iOS 15 推出之後,SwiftUI 框架為 List 視圖帶來了一個名為 searchable 的新修飾符 (modifier)。

在這篇教學文章中,我們會探討這個修飾符,看看為一個 List 實作搜尋有多簡單!

Searchable 的基本使用

Search-bar-ios15-demo

假設你已經創建了一個 List 視圖來顯示一系列文章,並希望提供一個搜尋欄來過濾文章。要將搜尋欄添加到 List 視圖,我們只需要宣告一個狀態變數 (state variable),來保存搜尋文本 (search text),並附加 searchable 修飾符到 NavigationView 即可:

struct SearchListView: View {

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

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

SwiftUI 會自動幫我們呈現搜尋欄,並將其放在 Navigation Bar 標題下。

swiftui-searchable-search-bar

在預設情況下,它會顯示 Search 為佔位符 (placeholder)。如果想更改它,你可以如此編寫 .searchable 修飾符,並設置自己的佔位符。

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

搜尋欄的位置

.searchable 修飾符有一個 placement 參數 (parameter),用於指定搜尋欄的位置。在預設情況下,它會設置為 .automatic。在 iPhone 上,搜尋欄位於 Navigation Bar 標題的下方。當我們向上滾動 List 視圖時,搜尋欄就會被隱藏。

searchable-permanent-search-bar-placement

如果想像上面這樣長期顯示搜尋欄,我們可以更改 .searchable 修飾符,並如此指定 placement 參數:

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

我們一直都將 .searchable 修飾符附加到 Navigation 視圖,其實我們也可以將它附加到 List 視圖,這樣在 iPhone 上都可以達到相同的效果。

不過,在 iPad OS 上使用 Splitview 時,.searchable 修飾符的位置就會影響搜尋欄的位置。讓我們看看下面的範例程式碼:

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

        .listRowSeparator(.hidden)

    }
    .listStyle(.plain)

    Text("Article Content")


    .navigationTitle("AppCoda")

}
.searchable(text: $searchText)

平常我們將 .searchable 修飾符附加到 Navigation 視圖中,在這種情況下,搜尋欄會顯示在 Split 視圖的 sidebar 上。

searchable-on-ipados

如果我們想將搜尋欄放在 detail 視圖中呢?我們可以將 .searchable 修飾符附加到範例程式碼的 Text 視圖中。

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

iPadOS 就會在 detail 視圖的右上角顯示搜尋欄。

searchable-ipados-search-bar

同樣,我們可以調整 placement 參數的值,來更改搜尋欄的位置。看看以下例子:

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

如果我們把 placement 參數設置為 .navigationBarDrawer,iPadOS 就會將搜尋欄放置在 Navigation Bar 標題的下方。

searchable-ipados-navigationbardrawer

執行搜尋並顯示搜尋結果

searchable-perform-search

我們有很多種方法可以過濾 Data List。我們可以創建一個實時執行資料過濾的計算屬性;或是附加 .onChange 修飾符,以追踪搜尋欄的改變。每當使用者在搜尋欄輸入內容時,就會實時執行搜尋。看看以下的範例程式碼片段:

NavigationView {
    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
    }
}

添加搜尋建議

我們可以利用 .searchable 修飾符來添加搜尋建議列表,以顯示一些常用的搜尋字詞或搜尋歷史。舉個例子,你可以這樣創建可點擊 (tappable) 的搜索建議:

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

以上的程式碼會顯示搜尋建議,當中有兩個可點擊的搜尋字詞。使用者可以輸入搜尋關鍵字,或是點擊搜尋建議來執行搜尋。

searchable-swiftui-perform-search

總結

iOS 15 為 SwiftUI 框架帶來了另一個備受期待的功能。.searchable 修飾符簡化了實作搜尋欄的步驟,並讓我們不需要創建解決方案,為我們節省了時間。唯一的缺點是這個功能僅適用於 iOS 15(或更新版本)。如果你正在構建需要支持舊版本 iOS 的 App,就還是需要構建自己的搜尋欄

譯者簡介:Kelly Chan-AppCoda 編輯小姐。
原文How to Implement Search for SwiftUI List Using Searchable


軟件工程師,AppCoda 創辦人。著有《iOS 13 App 程式設計實力超進化實戰攻略》、《iOS 13 App 程式設計實力超進化實戰攻略》以及《精通 SwiftUI》。曾任職於HSBC, FedEx等公司,專責軟體開發、系統設計。2012年創立AppCoda技術部落格,定期發表iOS程式教學文章。現時專注發展AppCoda,致力於iOS程式教學,產品設計及開發。

blog comments powered by Disqus
Shares
Share This