modifier 順序造成的 Value of type ‘some View’ has no member
透過串聯 SwiftUI 大量豐富的 modifier,我們可以快速客製 UI 元件的樣式,比方以下程式將 Agatha Christie 的電影尼羅河謀殺案海報裁切成圓形搭配黑色背景。
struct ContentView: View {
var body: some View {
Image(.deathOnTheNile)
.resizable()
.scaledToFill()
.frame(width: 300, height: 300)
.clipShape(.circle)
.background(.black)
.shadow(radius: 10)
}
}
不過 modifier 的順序要特別注意,剛剛的例子是先呼叫 clipShape 再 background,若是順序顛倒,將產生全然不同的結果。
struct ContentView: View {
var body: some View {
Image(.deathOnTheNile)
.resizable()
.scaledToFill()
.frame(width: 300, height: 300)
.background(.black)
.clipShape(.circle)
.shadow(radius: 10)
}
}
有時順序不對還會造成更可怕的後果,它會產生紅色錯誤,讓 App 完全跑不起來,比方我們在 Image 後先呼叫 scaledToFill,再呼叫 resizable。
此時將出現紅色錯誤
Value of type 'some View' has no member 'resizable'
為什麼不行呢
因為 function resizable 是型別 Image 的 function,然而 scaledToFill 的 function 定義如下。
func scaledToFill() -> some View
它回傳的型別是 some View,代表某一種 view,它可能是 Text,Button,Image 等,所以不能呼叫 resizable,因為唯有型別 Image 的東西能呼叫 resizable。
相反的,先呼叫 resizable,再呼叫 scaledToFill 是 ok 的。resizable 的定義如下。
func resizable(capInsets: EdgeInsets = EdgeInsets(), resizingMode: Image.ResizingMode = .stretch) -> Image
它會回傳 Image,而 function scaledToFill 來自 protocol View,因為 Image 遵從 protocol View,具有 View 的能力,所以從 Image 元件呼叫 scaledToFill 是可以的。
接著讓我們再看幾個 modifier 順序不對造成紅色錯誤的例子。
- Value of type ‘some View’ has no member ‘fill’
型別 some View 的東西不能呼叫 protocol Shape 的 function fill。(ps: Rectangle 遵從 protocol Shape,所以它可以呼叫 fill)
正確的 modifier 順序如下。
struct ContentView: View {
var body: some View {
Rectangle()
.fill(Color.red)
.frame(width: 200, height: 200)
}
}