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)
}
}

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com