SwiftUI: 利用Combine三種方式實時監聽用戶文本輸入

引子

自從Swift 5.1加入了Combine之後,腰不酸了,腿不疼了,各種姿勢都能有了…

我真不是在開車…

在這裏插入圖片描述

不過對於SwiftUI中的TextField來說如何實時監聽用戶輸入的文本呢?

貌似TextField自身並沒有帶用戶輸入改變的回調,這可咋整呢?

第一種方式:String.Publisher

在這裏插入圖片描述

沒關係,聰明的你們應該早已猜到,用Combine庫,秒天秒地秒空氣…

truct NameInputView: View{ 
    @State var name:String = ""

	var body: some View {
		var body: some View{
        VStack{
            Text("New keyword: ")
                .padding(.bottom)
            
            TextField("Keyword Content", text: $name){ 
            // 當用戶點擊返回按鈕時,關閉鍵盤
   			UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to:nil, from:nil, for:nil)
            }
	}

注意我們將name的綁定而不是單純name作爲TextField構造器的輸入。

在TextField最後加上一個modifer:

.onReceive(name.publisher){n in
	print("get \(n)")
}

上面我可以看到Combine對現有庫中的幾乎所有類型增加了擴展,自然包括String,我們利用這一特性,免費爲字符串name生成了一個發佈者,只要監聽它,就可以監聽用戶輸入的改變了 😉

在這裏插入圖片描述

但是先Wait一下,如果你實際運行代碼,你會發現監聽的結果不是你想要的字符串,而是一個個分散的字符.

比如你輸入abc,打印的將會是:

get a
get b
get c

它不是完整的返回字符串"abc",而是分別返回其中的每個字符…

這可不是我們想要的結果!

在這裏插入圖片描述

沒關係,別忘了Combine裏強大的操作符(Operators),你一定立即就能想到確認過眼神對的那一個:reduce!

reduce操作符的作用是將上層發佈者的Output進行聚合,然後作爲自己的輸出。

將.onReceive的調用按如下修改:

.onReceive(name.publisher.reduce("", {t,c in
            t + String(c)
        })){
		// 原代碼內容不變
}

再運行一下,啊哈!正是我們想要的!!!

在這裏插入圖片描述

上面就是第一種方式了,下面我們來看看還有沒有其他監聽輸入的方式了?

這是必須的!

第二種方式: CurrentValueSubject

Combine自帶了超多的Publisher和Operator,其中有一個CurrentValueSubject發佈者,可以爲你解憂:

let subject = CurrentValueSubject<String, Never>(name)

return
/*
原來的代碼
*/
.onReceive(subject){}

CurrentValueSubject是一個包含當前輸入值的發佈者,我們可以利用它來訪問當前保存的輸入值,非常方便!

第三種方式: String包裝器

最後一種方式是,雖然不能直接監聽String.Publisher,但是我們可以work around啊!

添加以下輔助類:

class StringWrapper: ObservableObject{
    @Published var name = ""
}

將View的name屬性類型修改爲StringWrapper:

@State private var nameWrapper = StringWrapper()

最後將監聽代碼修改如下:

.onReceive(nameWrapper.$name){}

OK!運行一下,你會發現結果都是相同的。

結語

本篇我們使用了三種不同方式完成了對SwiftUI中輸入框的監聽

留存以便本貓回憶,也希望大家能學到一丟丟東西。

感謝觀賞,再會!

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章