SwiftUI の View プロトコルには、onAppear と onDisappear と言う2つのイベントが定義されています。
onAppear は画面が表示された時に呼ばれ、UIViewController の viewDidAppear に該当します。
onDisappear は画面が表示されなくなった時に呼ばれ、こちらは viewDidDisappear に該当します。
ところが、画面が表示される前の viewWillAppear と、画面が表示されなくなる前の viewWillDisappear は現時点(2020年8月現在)では View プロトコルで定義されていません。
viewWillAppear なんかはよく使う場面が多かったので、需要がありそうなのに何故なんでしょうね?
理由はよくわかりませんが、必要なもので無いものは作るしかないのでちょっと調べてみたところ、こちらの記事で viewWillDisappear に対応をしていたので、ありがたく模倣させて頂きました。
その記事では viewWillAppear については触れていませんでしたが、要領は全く同じなので一緒に紹介します。
【SwiftUI】viewWillAppear と viewWillDisappear に対応する
viewWillAppear も viewWillDisappear の要領は同じです。
まず、UIViewControllerRepresentable プロトコルに準拠した構造体を作り、それを ViewModifier でカスタムView とし、されに View プロトコルの拡張(extension)として定義します。
ざっくりとした説明で分かりづらいかと思います(と言うか筆者の説明能力がない)ので早速コードを見ていきましょう。
onWillAppear の対応手順
ViewWillAppearHandler
struct ViewWillAppearHandler: UIViewControllerRepresentable {
func makeCoordinator() -> ViewWillAppearHandler.Coordinator {
Coordinator(onWillAppear: onWillAppear)
}
let onWillAppear: () -> Void
func makeUIViewController(context: UIViewControllerRepresentableContext<ViewWillAppearHandler>) -> UIViewController {
context.coordinator
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<ViewWillAppearHandler>) {
}
typealias UIViewControllerType = UIViewController
class Coordinator: UIViewController {
let onWillAppear: () -> Void
init(onWillAppear: @escaping () -> Void) {
self.onWillAppear = onWillAppear
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
onWillAppear()
}
}
}
ViewWillAppearModifier
struct ViewWillAppearModifier: ViewModifier {
let callback: () -> Void
func body(content: Content) -> some View {
content
.background(ViewWillAppearHandler(onWillAppear: callback))
}
}
onWillAppear
extension View {
func onWillAppear(_ perform: @escaping (() -> Void)) -> some View {
self.modifier(ViewWillAppearModifier(callback: perform))
}
}
onWillDisappear の対応手順
ViewWillDisappearHandler
struct ViewWillDisappearHandler: UIViewControllerRepresentable {
func makeCoordinator() -> ViewWillDisappearHandler.Coordinator {
Coordinator(onWillDisappear: onWillDisappear)
}
let onWillDisappear: () -> Void
func makeUIViewController(context: UIViewControllerRepresentableContext<ViewWillDisappearHandler>) -> UIViewController {
context.coordinator
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<ViewWillDisappearHandler>) {
}
typealias UIViewControllerType = UIViewController
class Coordinator: UIViewController {
let onWillDisappear: () -> Void
init(onWillDisappear: @escaping () -> Void) {
self.onWillDisappear = onWillDisappear
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
onWillDisappear()
}
}
}
ViewWillDisappearModifier
struct ViewWillDisappearModifier: ViewModifier {
let callback: () -> Void
func body(content: Content) -> some View {
content
.background(ViewWillDisappearHandler(onWillDisappear: callback))
}
}
onWillDisappear
extension View {
func onWillDisappear(_ perform: @escaping (() -> Void)) -> some View {
self.modifier(ViewWillDisappearModifier(callback: perform))
}
}
使用例
使用するときは、onAppear・onDisappear と同じく、任意の View 要素で宣言します(通常は最上位の View で宣言することが多い)。
struct ContentView: View {
var body: some View {
VStack {
Text("onWillAppear と onWillAppear")
}
.onWillAppear {
doSomething()
}
.onWillDisappear {
doSomething()
}
}
}
以上、onWillAppear と onWillDisappear に対応する手順を紹介しました。
UIKit にあって SwiftUI に無いものは他にもありますが、ありそうで無いものについては敢えて用意していないという可能性もあり、SwiftUI の設計思想をより深く理解していたら、そもそもの自分のプログラムに問題があって、「そんなカスタマイズ必要ないよ」ってこともあるかもしれませんね。
以上
コメントを残す