🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
iOS

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

Xcode

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

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

2871閲覧

Modalの遷移方法をcrossDissolveにするとポップアップの遷移元画面が真っ黒になる

prgramen

総合スコア19

iOS

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

Xcode

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

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2021/02/08 04:43

編集2021/02/08 10:30

現在Presentの遷移によるポップアップの作成をしています。
その際の遷移アニメーションをcrossDissolveにしたいのですが、crossDissolveにすると以下の画像のようにポップアップ遷移元画面が真っ黒になってしまいます。
coverVerticalとflipHorizontalを使用した場合は背景が保たれています。
なにか知見をお持ちの方、ご回答いただけるとありがたいです。

【うまくいく方:coverVerticalとflipHorizontal】
イメージ説明

【うまく行かない方:crossDissolve】
イメージ説明

Swift

1 2import UIKit 3 4class ViewController: UIViewController, UIViewControllerTransitioningDelegate { 5 6 override func viewDidLoad() { 7 super.viewDidLoad() 8 // Do any additional setup after loading the view. 9 } 10 11 @IBAction func showModal(_ sender: Any) { 12 let modalVC = self.storyboard?.instantiateViewController(identifier: "modal") 13 14//////////////////////////////////////////////////////////////////////////////////// 15 modalVC!.modalTransitionStyle = .crossDissolve 16//////////////////////////////////////////////////////////////////////////////////// 17 18 modalVC!.modalPresentationStyle = .custom 19 modalVC!.transitioningDelegate = self 20 present(modalVC!, animated: true, completion: nil) 21 } 22 23 func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { 24 return PresentationController(presentedViewController: presented, presenting: presenting) 25 } 26} 27 28//PresentationController.swift 29 30//import UIKit 31 32class PresentationController: UIPresentationController { 33 // 呼び出し元のView Controller の上に重ねるオーバレイView 34 var overlayView = UIView() 35 36 // 表示トランジション開始前に呼ばれる 37 override func presentationTransitionWillBegin() { 38 guard let containerView = containerView else { 39 return 40 } 41 overlayView.frame = containerView.bounds 42 overlayView.gestureRecognizers = [UITapGestureRecognizer(target: self, action: #selector(PresentationController.overlayViewDidTouch(_:)))] 43 overlayView.backgroundColor = .black 44 overlayView.alpha = 0.0 45 containerView.insertSubview(overlayView, at: 0) 46 47 /// ポップアップ元画面の透明度を濁らせる 48 presentedViewController.transitionCoordinator?.animate(alongsideTransition: {[weak self] context in 49 self?.overlayView.alpha = 0.5 50 }, completion:nil) 51 } 52 53 // 非表示トランジション開始前に呼ばれる 54 override func dismissalTransitionWillBegin() { 55 /// ポップアップ元画面の透明度をもとに戻す 56 presentedViewController.transitionCoordinator?.animate(alongsideTransition: {[weak self] context in 57 self?.overlayView.alpha = 0.0 58 }, completion:nil) 59 } 60 61 // 非表示トランジション開始後に呼ばれる 62 override func dismissalTransitionDidEnd(_ completed: Bool) { 63 if completed { 64 overlayView.removeFromSuperview() 65 } 66 } 67 68 // ポップアップのマージン 69 let margin = { () -> CGPoint in 70 // 端末の画面サイズ 71 let screenWidth = Double(UIScreen.main.bounds.size.width) 72 let screenHeight = Double(UIScreen.main.bounds.size.height) 73 74 let marginX = screenWidth * 0.13 75 let marginY = screenHeight * 0.44 76 77 return CGPoint(x: CGFloat(marginX), y: CGFloat(marginY)) 78 } 79 // 子のコンテナサイズを返す 80 override func size(forChildContentContainer container: UIContentContainer, withParentContainerSize parentSize: CGSize) -> CGSize { 81 return CGSize(width: parentSize.width - margin().x, height: parentSize.height - margin().y) 82 } 83 84 // 呼び出し先のView Controllerのframeを返す 85 override var frameOfPresentedViewInContainerView: CGRect { 86 var presentedViewFrame = CGRect() 87 let containerBounds = containerView!.bounds 88 let childContentSize = size(forChildContentContainer: presentedViewController, withParentContainerSize: containerBounds.size) 89 presentedViewFrame.size = childContentSize 90 presentedViewFrame.origin.x = margin().x / 2.0 91 presentedViewFrame.origin.y = margin().y / 2.0 92 93 return presentedViewFrame 94 } 95 96 // レイアウト開始前に呼ばれる 97 override func containerViewWillLayoutSubviews() { 98 overlayView.frame = containerView!.bounds 99 presentedView?.frame = frameOfPresentedViewInContainerView 100 presentedView?.layer.cornerRadius = 10 101 presentedView?.clipsToBounds = true 102 } 103 104 // レイアウト開始後に呼ばれる 105 override func containerViewDidLayoutSubviews() { 106 } 107 108 // overlayViewをタップした時に呼ばれる 109 @objc func overlayViewDidTouch(_ sender: UITapGestureRecognizer) { 110 /// ポップアップ元画面へ戻る 111 presentedViewController.dismiss(animated: true, completion: nil) 112 } 113}

試したこと
・modalPresentationStyleをoverCurrentContextにする
こちらの方法は、ポップアップが全画面表示になってしまい、
ポップアップとして機能しなくなってしまいます。

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

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

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

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

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

guest

回答2

0

ベストアンサー

ここまで作られているのであれば、トランジッションもカスタムで作られるのがいいかもしれません。

Asks your delegate for the transition animator object to use when dismissing a view controller.

上記のメソッドは UIViewControllerTransitioningDelegate として呼ばれるメソッドなので、

Swift

1 func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 2 return SlideAnimator(state: .dismissMenu, duration: 0.5) 3 } 4 5 func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { 6 return SlideAnimator(state: .appearMenu, duration: 0.5) 7 }

のような感じで、トランジッション用のクラス(UIViewControllerAnimatedTransitioning)を継承したサブクラスをかえせば実現できるかと思います。

手持ちのコードからのコピーですが、おそらくこれをそのままでつかうことができるのではないでしょうか。

UIView.amimate 周辺を変更されれば、スライドインに変更することももちろん可能です。

Swift

1class SlideAnimator: NSObject, UIViewControllerAnimatedTransitioning { 2 enum AnimationState { 3 case appearMenu 4 case dismissMenu 5 } 6 7 private var duration: Double 8 private var state: AnimationState 9 10 init(state: AnimationState, duration: Double) { 11 self.state = state 12 self.duration = duration 13 } 14 15 func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 16 return duration 17 } 18 19 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 20 let containerView = transitionContext.containerView 21 let viewToAppear = (state == .appearMenu) ? transitionContext.view(forKey: .to)! : transitionContext.view(forKey: .from)! 22 23 containerView.addSubview(viewToAppear) 24 25 viewToAppear.layer.opacity = (state == .appearMenu) ? 0 : 1 26 27 UIView.animate( 28 withDuration: duration, 29 delay: 0, 30 options: .curveEaseOut, 31 animations: { 32 viewToAppear.layer.opacity = (self.state == .appearMenu) ? 1 : 0 33 }, 34 completion: { bool in 35 transitionContext.completeTransition(true) 36 37 }) 38 39 return 40 } 41}

投稿2021/02/08 07:04

編集2021/02/08 07:06
TsukubaDepot

総合スコア5086

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

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

prgramen

2021/02/08 23:46

ありがとうございます。 思い通りのデザインにすることができました。
guest

0

遷移元画面を透過させる場合に使用するUIModalPresentationStyle.overCurrentContextの注意点

遷移元画面を透過させる方法として、 modalPresentationStyle を overCurrentContext にする方法がよく知られています。

投稿2021/02/08 06:04

dsuzuki

総合スコア1682

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

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

prgramen

2021/02/08 06:16

ご回答ありがとうございます。 こちらの方法ですが、modalPresentationStyleをoverCurrentContextにすると、 ポップアップが全画面表示になってしまい、 ポップアップとして機能しなくなってしまいます。
dsuzuki

2021/02/08 06:37

私がよくやる方法は、背景を透明にした全画面表示ViewControllerをoverCurrentContextで表示させます。 ダイアログ部分は、背景を透明にしたViewControllerの中央にsubViewとして配置します。
prgramen

2021/02/08 23:50

なるほど!もしサンプルコードなどあれば拝見したいです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問