為什么 SwiftUI 的修飾符順序很重要
本文轉(zhuǎn)載自微信公眾號「Swift社區(qū)」,作者韋弦Zhy。轉(zhuǎn)載本文請聯(lián)系Swift社區(qū)公眾號。
每當我們將修飾符應(yīng)用于 SwiftUI 視圖時,我們實際上都會創(chuàng)建一個,應(yīng)用了更改的新視圖 —— 我們不僅僅是修改現(xiàn)有的視圖。 如果你仔細想想,這種行為是有道理的 —— 我們的視圖僅保留我們賦予它們的確切屬性,因此,如果我們設(shè)置背景顏色或字體大小,則無處存儲該數(shù)據(jù)。
我們將在下一章中查看為什么會發(fā)生這種情況,但是首先,我想看看這種行為的實際含義??匆幌逻@段代碼:
- Button("Hello World") {
- // do nothing
- }
- .background(Color.red)
- .frame(width: 200, height: 200)
您認為它運行時會是什么樣?
您很可能猜錯了:您不會在中間看到帶有 “Hello World” 的 200x200 紅色按鈕。相反,您會看到一個 200x200 的空正方形,中間是 “Hello World”,在 “Hello World” 周圍有一個紅色矩形。
如果思考一下修飾符的工作原理,您就可以了解為什么會如此:每個修飾符都會創(chuàng)建一個,應(yīng)用了該修飾符的新結(jié)構(gòu)體,而不是在視圖上設(shè)置屬性。
您可以通過查詢視圖主體的類型來窺視 SwiftUI 的底層。將按鈕修改為如下:
- Button("Hello World") {
- print(type(of: self.body))
- }
- .background(Color.red)
- .frame(width: 200, height: 200)
Swift 的 type(of:) 方法會打印特定值的確切類型,在這種情況下,它將打印以下內(nèi)容:ModifiedContent
您可以在這里看到兩件事:
- 每次我們修改視圖時,SwiftUI 都會使用以下泛型來應(yīng)用該修飾符:ModifiedContent
- 當我們應(yīng)用多個修飾符時,它們會疊加在一起:ModifiedContent
要了解該類型是什么,請從最里面的類型開始,然后逐步解決:
- 最里面的類型是 ModifiedContent
- 在外部,我們有了 ModifiedContent<…, _FrameLayout> ,它使用了我們的第一個視圖(按鈕+背景色),并為其提供了 Frame。
如您所見,我們使用 ModifiedContent 類型堆疊——每個視圖都需要一個視圖進行轉(zhuǎn)換以及要進行的實際更改,而不是直接修改視圖。
這意味著修飾符的順序很重要。 如果我們重寫代碼以便在設(shè)置 Frame 后使用背景色,那么您就會得到預(yù)期的結(jié)果:
- Button("Hello World") {
- print(type(of: self.body))
- }
- .frame(width: 200, height: 200)
- .background(Color.red)
現(xiàn)在最好的思考方法是,想象一下 SwiftUI 在每個修飾符之后都會呈現(xiàn)您的視圖。因此,只要您說 .background(Color.red),它就會將背景顏色變?yōu)榧t色,而不管您給它什么 Frame。如果您之后再擴展 Frame,它將不會重新加載因為背景已經(jīng)被使用了。
當然,這不是 SwiftUI 實際上的工作方式,因為如果這樣做,那將是性能上的噩夢,但這是學(xué)習的時候可以使用的一種簡潔的思維捷徑。
使用修飾符的一個重要副作用是,我們可以多次應(yīng)用相同的效果:每個修飾符都會簡單地添加到以前的內(nèi)容中。
例如,SwiftUI 為我們提供了 padding() 修飾符,該修飾符在視圖周圍添加了一些空間,從而不會將其推到其他視圖或屏幕邊緣。如果我們應(yīng)用填充,然后應(yīng)用背景色,然后應(yīng)用更多填充和不同的背景色,則可以為視圖提供多個邊框,如下所示:
- Text("Hello World")
- .padding()
- .background(Color.red)
- .padding()
- .background(Color.blue)
- .padding()
- .background(Color.green)
- .padding()
- .background(Color.yellow)
譯自 Why modifier order matters[1]
參考資料
[1]Why modifier order matters: https://www.hackingwithswift.com/books/ios-swiftui/why-modifier-order-matters