3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TCAでsheet表示されたView自身からsheetを閉じる方法

Last updated at Posted at 2021-04-10

はじめに

The Composable Archtecture (TCA) でsheet表示したViewを表示した側から閉じる方法について、とりあえず1パターンだけ示しておきます。

結論

  • SwiftUIのおさらい
    • SwiftUIではsheetとして表示したViewを閉じる方法としてEnvironmentValuesとしてPresentationModeがある
      • PresentationModedismiss()メソッドでViewを閉じれる
        • Viewのみに限定したロジックでViewを閉じたいときはこれだけでいい
  • TCAでReducerの処理からViewを閉じたい場合どうするか
    • Stateの変数が変わった場合、SwiftUIのonChange(of:)メソッドが検知できる
      • onChange(of:)メソッドのクロージャでPresentationModedismiss()を呼び出す

詳細

SwiftUIではsheetとして表示したViewを閉じる方法としてEnvironmentValuesとしてPresentationModeがある

サンプルコードとしてContentViewがChildViewをsheetで開き、ChildViewのPresentationModedismiss()メソッドで自身を閉じれる。

スクリーンショット 2021-04-10 12.05.47.png
)`

//: A UIKit based Playground for presenting user interface
  
import UIKit
import SwiftUI
import PlaygroundSupport

struct ContentView: View {

    @State var isPresented = false

    var body: some View {
        NavigationView {
            Button(
                action: {
                    print("action:", isPresented) // => false
                    isPresented = true
                },
                label: {
                    Text("Present View")
                }
            )
            .sheet(isPresented: $isPresented) {
                ChildView()
            }
        }
    }
}

struct ChildView: View {
    @Environment(\.presentationMode) var presentationMode

    var body: some View {
        Button(
            action: {
                presentationMode.wrappedValue.dismiss()
            },
            label: {
                Image(systemName: "xmark.square")
                Text("Close")
            }
        )
    }
}

PlaygroundPage.current.liveView = UIHostingController(rootView: ContentView())

Viewのみに限定したロジックでViewを閉じたいときはこれだけでいい。

コメントをもらったので気づけた話として、ContentViewのisPresentedはChildViewを閉じればfalseになってる。

これは$isPresentedとして$をつけることで@Stateからvar projectedValue: Binding<Value> { get }を取り出せているから。そのために.sheet(isPresented: $isPresented)seetからfalseにできる。

TCAでReducerの処理からViewを閉じたい場合どうするか

StateのBoolを用意し、onChange(of:)でviewStoreを見張ってその変化時にpresentationModeを操作すればいい。

struct ChildSttate {
    var isPresented = true
}

struct ChildView: View {
    @Environment(\.presentationMode) var presentationMode

    let store: Store<ChildState, ChildAction>

    var body: some View {
        WithViewStore(store) { viewStore in
            Button(
                action: {
                    presentationMode.wrappedValue.dismiss()
                },
                label: {
                    Image(systemName: "xmark.square")
                    Text("Close")
                }
            )
            .onChange(of: viewStore.isPresented) { value in
                if !value {
                    presentationMode.dismiss()
                }
            }
        }
    }
}

参考

3
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?