Swift Practice # 153 SwiftUI GeometryReader 與Safe Area初探

Dogpa Chen
8 min readMay 14, 2022

--

上一篇理解了CLLocation的使用方式去取得指定的兩個經緯度直線距離,大概知道如何實作在side project上。

大致的前置作業都完成,準備開始寫side project,但是腦海思索著一個問題,當初在UIKit能透過Storyboard來處理元件跟Safe Area的問題,畢竟在瀏海機與舊指紋機兩者個Safe Area有著大大的不同,為了避開元件顯示的問題,我自己會盡量把元件放在Safe Area,避免遭遇到瀏海與其他的狀況。

UIKit的Safe Area 位置與尺寸

透過Safe Area 建立View的位置與大小
Safe Area 初始的位置與大小

上面三張圖片讓元件透過去equal Safe Area去綁定元件的大小,大致透過這樣的方式使元件不會超過Safe Area。從上圖iPhone 12 Pro得知我們需要的一些尺寸數值

Screen Size:390 × 844

Safe Area:390 × 763

上方狀態欄height:47

下方Home Indicator height:Screen Size 減 Safe Area 減狀態欄 等於 34。

不過可以注意到右上方的圖height都是766為什麼會是763?這產生了我的好奇,所以我重新做了一個跟Safe area比例1:1的Button來查看尺寸。

從上圖得知Safa Area的高是763沒錯,另外得知上方的狀態欄的高是47,從這邊確認好UIKit看到的iPhone 12 Pro的Safe Area的定位與寬高。至於UIkit的height766就讓我們後續再理解了。

SwiftUI GeometryReader 初探

先嘗試透過官方說明來理解GeometryReader的說明:

A container view that defines its content as a function of its own size and coordinate space.This view returns a flexible preferred size to its parent layout.

可以理解的是可以協調View的空間,更加靈活的處理與父層的layout。可以從官方得知,這不是完全拿來處理Safe Area的問題。就我目前的一部分理解,SwiftUI在預設空間時,會將View放在Safe Area內,除非我們使用了.ignoresSafeArea()。下方的程式碼讓我自己確認View的處理會在Safe Area內執行。

從上圖加總可已得到762.9視為763,也就是跟Safe Area的height一樣。

SwiftUI GeometryReader 與 Safe Area

從網路上的資源得知,GeometryReader可以取得Safe Area的尺寸,嘗試列印確認尺寸大小。

在SwiftUI中 iPhone 12 Pro 的 GeometryReader的Size是390與763,跟UIKit的Safe Area的尺寸一樣。

GeometryReader 近似視圖深度

從上面的程式碼與圖片可以看到在沒有設定Vstack或是Zstack的狀態,在GeometryReader內是類似像是ZStack一樣,不是像some view內會依序排列。這是在練習當中的一個發現。

GeometryReader 與 Spacing

上圖的程式碼中可以發現到我們透過Geometry的寬度/3設置Text與Button,但是系統自動幫我們做出了白色間距,截圖看了一下這白色間距的距離為8,從這點可以看到SwiftUI會自動產生height8的spacing,再注意上方GIF內下方可以看到三個元件的高是254.3。

下面我嘗試設定spacing為0並再確認結果。

從上面的GIF內可以看到白色間距已經不見了,但觀察到了一件事,不管有沒有設定spacing,三個元件的height都是254.3,但又讓我產生疑問,那到底spacing的距離會不會影響佈局?這個時候我回去查看沒有預設spacing的程式碼確認GeometryReader內VStack的尺寸。

上圖內發現到整個VStack已經變成779,超越了Safe Area的763,而差距也可以得知是16兩個spacing各自為8的height。從這點可以看到若是我們沒有特別設定spacing,整個GeometryReader的尺寸將會超過Safe Area,在使用上可能會造成Home indicator遮擋,因為整個高是從上方的狀態欄47的height去開始往下調整,所以會影響到的就是下方的Home indicator。

GeometryReader上下方的SafeArea顏色

從上方的程式碼與Preview可以看到spacing為0 GeometryReader的VStack的height為763,但Preview的圖可以看到上方的SafeArea被渲染成紅色,下方則為綠色,這又帶來了下一個問題,如果想要讓Safe Area不要被自動渲染,該怎麼處理?

方法一:

第一個方法我透過包覆一層ZStack放入顏色當作背景色,再放入一個Text,透過這個方法上下方的Safe就沒有被渲染成紅色與綠色。

方法二:

方法二則透過在.background來處理,塞入指定的形狀的顏色背景

透過上面兩個方法,可以讓Safe Area不會自動地去渲染靠近他的顏色,目前還不確定是什麼原因造成的,但至少先透過解法來解決問題,而造成問題的原因也是未來要慢慢去理解的事,搞懂怎麼用跟成因還是相對重要的。

GeometryReader 與 Safe Area 可以不一樣大小

上圖的Gif可以看到GeometryReader的大小變成655,原因在於同一個VStack內我們還存在著一個height100的Text,加上自動spacing的height8組成了整個763的Safe Area的大小。從這點來看可以得知GeometryReader不一定是完全跟Safe Area一樣大。

上述就是自己關於GeometryReader的認識,本質上來說Safe Area的空間算是GeometryReader的一個延伸,並不只是完全可拿來聚焦在Safe Area,只是剛好你使用在最外層,那GeometryReader就可以跟Safe Area達到一致在透過size的比例去指定元件跟SafeArea大小的相對關係,但這也要注意到spacing產生的空間問題,認真思考SwiftUI帶來了便利性,但深度鑽研還是可以發現很多系統幫你處理好,但你想自己設定的一些狀況與可能性。持續加油!!

--

--

Dogpa Chen
Dogpa Chen

Written by Dogpa Chen

Smile Coding / iOS轉職路ING

No responses yet