剛剛做好了 WebView,然後我們需要一個 button,在點擊之後把一個新的 View 從下方滑到上方。這個過場在 iPhone 裡面是非常常見的操作,先做一個 Button 在 ClockContainerView 上方。
var body: some View {
ZStack {
VStack {
Button {
// TODO: - 發動彈窗
} label: {
Image(systemName: "person.crop.circle")
.font(.system(size: 50))
.foregroundColor(.brown)
}
Spacer()
}
Group {
ClockDialView()
HandShape(handLength: .hour)
.fill(Color.blue)
.rotationEffect(Angle(degrees: clockwork.hourAngle))
HandShape(handLength: .minute)
.fill(Color.cyan)
.rotationEffect(Angle(degrees: clockwork.minuteAngle))
HandShape(handLength: .second)
.fill(Color.red)
.rotationEffect(Angle(degrees: clockwork.secondAngle))
Circle()
.fill(Color.orange)
.frame(width: 20, height: 20, alignment: .center)
}
.frame(width: width, height: height, alignment: .center)
}
}
這個 Profile Button,按下去後會將 Grace Hopper 的 wiki 頁面,從下方彈出來。
如 D3(補上連結) 所說,SwiftUI 的框架,要讓 View 改變,就要讓 State 改變,接下來框架就會幫你做完剩下的事情。在 SwiftUI 裡面,類似 UIKit 的 present 的形為,呼叫為 sheet,isPresented 是綁定一個布林值,如果為 true,就呈現,反之,就縮下去。onDismiss 可以不寫動作,最後的 content,就是你要呈現的 view。
SwiftUI 對 Sheet 的說明文件。
https://developer.apple.com/documentation/SwiftUI/View/sheet(isPresented:onDismiss:content:)
在 View 裡面,先宣告這個需不需要 present 的 State 變數。
@State private var isShowingGraceWikiSheet = false
/// Grace Hopper Wiki 網址
private let graceWikiPageURL = "https://en.wikipedia.org/wiki/Grace_Hopper"
然後更改上方程式碼中的 Button,Button 需要發動 toggle(),讓 isShowingGraceWikiSheet 切換,並把 sheet modifier 加上。
Button {
isShowingGraceWikiSheet.toggle()
} label: {
Image(systemName: "person.crop.circle")
.font(.system(size: 50))
.foregroundColor(.brown)
}
.sheet(isPresented: $isShowingGraceWikiSheet) {
BCWebView(urlString: graceWikiPageURL)
}
這樣,在點擊 Button 後,就能彈出 Grace Hopper 的 wiki 頁面了。
這個 present 的效果,是有自帶由上往下滑動後,把前面的 view dismiss 掉。不過如果你彈出來的是個可以上下滑動的頁面,那在模擬器上滑起來,就會變得不容易觸發 dismiss。
解法是有的,就是在彈出來的這個頁面,加上一個可以觸發自己 dismiss 的 button,讓外面滑不動的時候,彈起來的頁面還可以 dismiss。稍微修改一下 BCWebView。
struct BCWebView: View {
@Environment(\.dismiss) var dismiss
let urlString: String
var body: some View {
if let url = URL(string: urlString) {
VStack {
HStack {
Spacer()
Button {
dismiss() // 讓這一頁發動 dismiss
} label: {
Image(systemName: "x.circle")
.font(.system(size: 44))
.tint(.black)
.padding([.top, .trailing])
}
}
WKWebViewContainer(url: url)
}
} else {
URLNotCorrectView()
}
}
}
現在,試著點擊一下彈起來的 wiki 頁面右上方 X,如果手勢沒辦法發動,就可以用這個 X 來發動 dismiss。