利用 GeometryReader 取得 SwiftUI 元件的座標尺寸
設計 SwiftUI App 畫面時,我們通常不太需要思考元件的座標尺寸,不過有時我們會想知道元件在整個螢幕的座標尺寸,或是它相對於某個 view 的座標。
這些願望要實現並不難,只要透過 GeometryReader 的幫忙。
取得元件在整個螢幕的座標尺寸
struct ContentView: View {
var body: some View {
Image("tony")
.resizable()
.scaledToFit()
.frame(width: 300)
.overlay(
GeometryReader(content: { geometry in
Text(geometry.frame(in: .global).debugDescription)
.background(Color.yellow)
})
)
}
}
我們以男神梁朝偉在 FB 分享的帥氣圖片為例,想知道它在整個螢幕的座標尺寸。
取得座標尺寸的關鍵在以下程式
.overlay(
GeometryReader(content: { geometry in
Text(geometry.frame(in: .global).debugDescription)
.background(Color.yellow)
})
)
在 Image
上呼叫 overlay
modifier,然後傳入包含 Text
的 GeometryReader
。GeometryReader
是個看不到的容器,它的參數 geometry
可告訴我們它的位置大小。由於我們以 overlay
將 GeometryReader
疊在 Image
上,所以它的位置大小即是 Image
的位置大小。
參數geometry
的型別是 GeometryProxy
,我們呼叫它的 function frame(in:)
,傳入參數 .global
取得相對於整個螢幕的座標尺寸。若想單獨取得座標和尺寸,可透過 geometry.frame(in: .global).origin
& geometry.frame(in: .global).size
。
將元件的座標尺寸存在變數裡
有些時候我們希望能將元件的座標尺寸存在變數裡,方便之後讀取。這要怎麼做到呢 ?
由於 GeometryReader 的參數 content 裡一定要生成 view,所以我們可以生成看不到的 Color.clear,然後在它身上加上 onAppear modifier,如此即可在 Color.clear 出現時取得 GeometryReader 的座標尺寸,然後存在變數裡。
struct ContentView: View {
@State private var orangeFrame = CGRect.zero
var body: some View {
VStack(spacing: 0) {
Color.blue
.frame(width: 50, height: 80, alignment: .center)HStack(spacing: 0) {
Color.blue
.frame(width: 50, height: 50, alignment: .center)
Color.orange
.frame(width: 200.0, height: 200.0)
.overlay(
GeometryReader(content: { geometry in
Color.clear
.onAppear(perform: {
orangeFrame = geometry.frame(in: .global)
})
})
)
.onTapGesture {
print(orangeFrame)
}
Spacer()
}
Spacer()
}
.edgesIgnoringSafeArea(.all)
}
}
點選橘色長方形將印出以下座標尺寸。
(50.0, 80.0, 200.0, 200.0)
取得元件相對於 parent 的座標
有時我們想取得元件相對於 parent 的座標,比方以下偉仔相對於藍色 stack view 的座標。
struct ContentView: View {var body: some View {
VStack {
Image("tony")
.resizable()
.scaledToFit()
.frame(width: 300)
.overlay(
GeometryReader(content: { geometry in
Text(geometry.frame(in: .named("blue view")).debugDescription)
.background(Color.yellow)
})
)
}
.frame(width: 400, height: 600)
.background(Color.blue)
.coordinateSpace(name: "blue view")
}
}
此問題的難度高了一點,找出答案的關鍵在以下幾行程式
.coordinateSpace(name: "blue view")
從 VStack 呼叫 coordinateSpace(name:),給它名字 blue view,之後即可找出相對於 blue view 的座標。
.overlay(
GeometryReader(content: { geometry in
Text(geometry.frame(in: .named("blue view")).debugDescription)
.background(Color.yellow)
})
)
同樣呼叫 function frame(in:)
,不過這次我們傳入 .named("blue view")
,.name( ) 裡傳入 blue view 表示我們想找出元件相對於 blue view 的座標。