SwiftUI 教學:使用 SwiftUI 來打造 Search Bar 原來那麼簡單!


最近,我收到一個問題,關於在 SwiftUI 專案中實作 Search Bar。與 UIKit 不同,SwiftUI 沒有內建的 Search Bar 物件可以使用。你或許可以使用 UIViewRepresentable 協定,以在 SwiftUI 專案中重用 UIKit 的 UISearchBar。但要使用純 SwiftUI 的方式來實作一個 Search Bar,其實並不困難。在這次的教學中,就讓我們來建立一個 SwiftUI 版的 Search Bar!

看看以下這張圖片,我們即將要打造一個這樣的 Search Bar。它看起來跟 UIKit 的 UISearchBar 沒什麼兩樣。而我們還會實作一個 Cancel 按鈕,按鈕只會在使用者開始在搜索欄打字時才會出現。

Building a Search Bar in SwiftUI 1

編者備註:如果你還不熟悉 SwiftUI,可以先閱讀我們的入門教學

實作 Search Bar UI

為了讓你專注於實作 Search Bar,你可以先下載這個初始專案,並編譯一次,以確保它執行無誤。這個 App 會顯示一個待辦事項的列表。現在,讓我們實作 SearchBar.swift 檔案來建立一個 Search Bar。

仔細觀察一下 iOS 裡面內建的標準 Search Bar,你會發現它是由一個文字輸入框 (text field) 和 Cancel 按鈕所組成的。

import SwiftUI

struct SearchBar: View {
    @Binding var text: String

    @State private var isEditing = false

    var body: some View {
        HStack {

            TextField("Search ...", text: $text)
                .padding(7)
                .padding(.horizontal, 25)
                .background(Color(.systemGray6))
                .cornerRadius(8)
                .padding(.horizontal, 10)
                .onTapGesture {
                    self.isEditing = true
                }

            if isEditing {
                Button(action: {
                    self.isEditing = false
                    self.text = ""

                }) {
                    Text("Cancel")
                }
                .padding(.trailing, 10)
                .transition(.move(edge: .trailing))
                .animation(.default)
            }
        }
    }
}

首先,我們定義了兩個變數:一個是搜尋文字的 Binding,另一個用來儲存目前搜索欄的狀態(是否正在編輯中)。

接著,我們使用了 HStack 來編排文字輸入框跟 Cancel 按鈕的位置。按鈕只會在使用者點擊了搜索欄時才會顯示。為了預覽我們實作的 Search Bar,請輸入以下的程式碼:

struct SearchBar_Previews: PreviewProvider {
    static var previews: some View {
        SearchBar(text: .constant(""))
    }
}

加入了這些程式碼之後,你應該能夠預覽整個搜索欄。點擊 Play 按鈕來測試這個搜索欄。現在,當你點擊文字輸入框之後,就會出現 Cancel 按鈕了。

swiftui-search-bar-xcode-preview

目前這個版本的 Search Bar,還缺少了兩個要素:就是 Search Icon 和 Cross Icon。我們可以在文字輸入框附加 overlay 修飾器,來加入這些 icon。將以下的程式碼放在 .cornerRadius(8) 的後面:

.overlay(
    HStack {
        Image(systemName: "magnifyingglass")
            .foregroundColor(.gray)
            .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
            .padding(.leading, 8)

        if isEditing {
            Button(action: {
                self.text = ""
            }) {
                Image(systemName: "multiply.circle.fill")
                    .foregroundColor(.gray)
                    .padding(.trailing, 8)
            }
        }
    }
)

我們為文字輸入框加上了兩個系統圖片,而 multiply.circle.fill 只會在使用者開始在搜索欄打字時顯示。當這個圖片被點擊時,它會將搜索欄重設成空白的狀態。你可以點擊 Play 按鈕,以在預覽視窗測試 Search Bar。

使用 Search Bar 來過濾資料

現在,我們已經準備好 Search Bar。接下來,讓我們切換到 ContentView.swift,將它加入到 list view 裡面吧。

List View 之前,加入以下的程式碼:

SearchBar(text: $searchText)
    .padding(.top, -30)

這樣,我們就功成在 title 跟 list view 之間加上了 Search Bar。
searchText 是一個狀態變數 (state variable),持有我們即將搜尋的文字。它會隨著使用者的在搜索欄所輸入的內容,來更新要搜尋的文字。

我們需要如此更新 List view 來過濾結果:

List(todoItems.filter({ searchText.isEmpty ? true : $0.name.contains(searchText) })) { item in
    Text(item.name)
}

在這段程式碼中,我們使用了 filter 函式來尋找符合搜尋文字的待辦事項。在這一段閉包中,我們先檢查了 searchText 有沒有值。如果沒有的話,我們就回傳 true,也就是會回傳全部的待辦事項。相反,如果 searchText 有值的話,就檢查待辦事項的名稱欄位是否有包含搜尋的文字。

讓我們試試執行 App 吧,結果應該會依照你所輸入的文字來找到待辦事項。

swiftui-search-bar-typing

將鍵盤收起來

如你所見,完全用 SwiftUI 打造一個 Search Bar,並不是困難的事情。可是,雖然現在它可以正常運作,但還有一個小問題需要修正。不知道你有沒有嘗試點擊 Cancel 按鈕?它的確會清除搜索欄的內容,但是虛擬鍵盤卻沒有消失。

為了修正這一點,我們需要在 Cancel 按鈕的 action block 加上一行程式碼:

// Dismiss the keyboard
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)

在這一段程式碼中,我們呼叫了 sendAction 方法,來解除目前的 first responder,並收起了虛擬鍵盤。現在你可以重新執行模擬器,你會發現當你點擊 Cancel 按鈕時,它就會清除搜索欄,並且將虛擬鍵盤收起來了。

總結

在這篇教學中,我們展示了如何實作一個 Search Bar。如你所見,這個過程並不困難。如果你想深入鑽研管理資料庫內容的技巧,可以參考我們的 《精通SwiftUI》電子書。在書本中,我們會更進一步地展示如何使用 Core Data 來保留資料,以及使用 fetch request 來處理搜尋的功能,而且你還可以取得一個待辦事項 App 完整的原始碼。

你可以在這邊下載完整專案作參考。

譯者簡介:周竑翊 – 只待過新創公司的 iOS 開發者,本職是兩個兒子的爸。有空的時間喜歡看看新的技術跟科技時事。用 Playground 寫寫 Swift,但是 side project 仍然難產。其他興趣喜歡攝影、運動及看電影。歡迎寄信與我聯絡:[email protected]

原文:Building a Search Bar in SwiftUI for iPad and Mac


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

blog comments powered by Disqus
Shares
Share This