質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Q&A

解決済

2回答

1787閲覧

SwiftUIでモーダルAからモーダルBへ連続して画面遷移させたい

ch3cooh

総合スコア287

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

0グッド

0クリップ

投稿2020/07/25 07:38

編集2020/07/26 09:46

前提・実現したいこと

ImagePickerで画像を選択したあと、選択した画像をクロッピング処理への遷移を想定しています。

イメージ説明

画像云々の部分はあまり関係ない話ですので、ここでは便宜上画面A・画面Bと表現します。

実現したいこととしては、下記の通りです。

  1. 画面Aをモーダル表示する
  2. 画面Aを閉じられると、画面Bをモーダル表示する
  3. その後、画面Bが閉じられること

画面Aを開いて閉じて、画面Bを開いて閉じて、の動作をSwiftUIでスムーズにできるようになりたいです。

発生している問題・エラーメッセージ

現在発生している問題は、

  • 画面Aを閉じたあと、すぐに画面Bを表示した場合、画面Bは閉じられない (dismissが効かなくなる)
  • 画面Aを閉じたあと、1秒待ってから画面Bを表示した場合、画面Bは閉じられる

現在、画面A -> (1秒待ち) -> 画面B となっているので、この1秒待ちをなくしたいと考えています。

該当のソースコード

import SwiftUI struct SampleTwoModalView : View { enum SheetType { case imagePick case imageCrop } @State private var currentSheet: SheetType = .imagePick @State private var sheetIsPresented = false @State private var image: UIImage? = nil var body: some View { VStack { Button(action: { self.currentSheet = .imagePick self.sheetIsPresented = true }, label: { Text("select images & crop images") }) } .sheet(isPresented: $sheetIsPresented) { if (self.currentSheet == .imagePick) { ImagePickerView(sourceType: .photoLibrary, onCanceled: { // on cancel }) { (image) in self.image = image //画像を選択するとクロッピング画面へ遷移させる (X) DispatchQueue.main.asyncAfter(wallDeadline: .now() + .milliseconds(1000)) { self.currentSheet = .imageCrop self.sheetIsPresented = true } } } else if (self.currentSheet == .imageCrop) { ImageCropView(originalImage: self.image!, onCanceled: { // on cancel }) { (image) in // on success } } } } }

試したこと

(X)の処理を下記のようにすると、画面Bへの遷移はできるが、画面Bをdismissできない状態になります。

//画像を選択するとクロッピング画面へ遷移させる (X) DispatchQueue.main.async { self.currentSheet = .imageCrop self.sheetIsPresented = true }

補足情報(FW/ツールのバージョンなど)

  • Xcode 11.6
  • iOS 13.3, iOS 13.6

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ch3cooh

2020/07/31 02:07

環境自体は Xcode 11.6 + iOS 13.6 (Sim) でしたが、検証方法は合ってます! dismissアニメーション中に `sheetIsPresented`を`true`にしてシートを表示させることで内部的なフラグ(?)がおかしくなっているのではないかと推測しているのですが、 Xcode 11.5と11.6 (もしくは iOS 13.5と13.6)で違いがあるのでしょうか。
fuzzball

2020/07/31 02:23

SwiftUIをチビチビ勉強中で、勉強がてら覗いてみただけなんです。 なので詳しいことはよく分かりません。 あとでXcode落としてみます。
fuzzball

2020/07/31 05:00 編集

11.6でも正しく動いたのでおかしいな‥と思ったら、SchemeがSwiftUIじゃないやつになってました。失礼しました‥。
guest

回答2

0

一つ前のブランチ 43c0580 からの修正です。
偶然見つけただけで、どれほど正しいのか分かりませんが、合っているような雰囲気はあります。

swift

1ImagePickerView(croppingStyle: self.croppingStyle, sourceType: .photoLibrary, onCanceled: { 2 // on cancel 3}) { (image) in 4 self.originalImage = image 5}.onDisappear() { 6 self.currentSheet = .imageCrop 7 self.sheetIsPresented = true 8}

投稿2020/07/31 05:41

編集2020/07/31 05:44
fuzzball

総合スコア16733

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ch3cooh

2020/07/31 06:24

シートに対してonDisappear Modifierで閉じたタイミングが取得できるんですね。これはアリです!!ありがとうございます。 ただ使ってるのが UIViewControllerRepresentable でラップしたUIKitなので、UIKit側でdismissした方が良いのか悩ましいですね。
guest

0

自己解決

dismissアニメーション中に次の画面をモーダル表示させることで、SwiftUI内部のステータス管理が不正な状態になってしまうのが原因ではないかと考えています。今後のSwiftUIの修正に期待したい部分です。

またSwiftUI側ではdismissが完了したタイミングを取得できないため、dismissが終了してすぐに次の画面へ遷移できません。

私の結論としては、Xcode11.6時点ではUIImagePickerControllerなどのUIKitを使っている以上、SwiftUIで連続してスムーズにモーダル画面を表示するのは難しいので、UIKit側でdismissのタイミングを取る、でした。

本質部分ではないので、ここでは該当部分のみを転記したいと思います。イメージとしては以下の通りです。

swift

1public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { 2 guard let image = info[.originalImage] as? UIImage else { 3 picker.dismiss(animated: true) { 4 self.onImagePicked(nil) 5 } 6 return 7 } 8 9 // UIKit側で閉じるのを待ってからSwiftUI側に画像を渡す 10 picker.dismiss(animated: true) { 11 self.onImagePicked(image) 12 } 13}

ソースコードは下記のリポジトリで参照可能です。

投稿2020/07/29 00:32

ch3cooh

総合スコア287

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問