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

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

新規登録して質問してみよう
ただいま回答率
85.35%
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

解決済

1回答

1238閲覧

カスタムアニメーションで遷移後にラベルの位置がずれてしまう

Ka_ya_

総合スコア31

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クリップ

投稿2020/05/18 10:47

質問失礼します。

遷移元にある特定のイメージビューやラベルをそれぞれ個別のアニメーションをさせて画面遷移したいのですが、
遷移先のラベルをせり上がるアニメーションで遷移後の画面のラベル位置で止めようとすると、
gif画像の様に位置にズレが発生してしまいます。

アニメーション時の
animationLabel.frame = secondViewController.secondLabel.frame.offsetBy(dx:0, dy:0)
こちらのコード記載で、次画面にあるラベルと同じサイズ・位置が指定出来ていると考えているのですが、
そうすると位置は指定出来てもframeのサイズ変更の指定はどうすればいいのかも分からず、
いまいちアニメーションの指定方法が理解出来ずにいます。

どなたかご教授いただけますと嬉しいです。
よろしくお願い致します。

・遷移元のビューコントローラー

Swift

1import UIKit 2 3class ViewController: UIViewController, UIViewControllerTransitioningDelegate { 4 5 let loginTransition = LoginTransition() 6 7 @IBAction func loginButton(_ sender: Any) { 8 9 let topVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "top") 10 11 topVC.modalPresentationStyle = .overCurrentContext 12 topVC.transitioningDelegate = loginTransition 13 14 present(topVC, animated: true, completion: nil) 15 } 16 17 18 @IBOutlet weak var firstImageView: UIImageView! 19 @IBOutlet weak var firstLabel: UILabel! 20 21 override func viewDidLoad() { 22 super.viewDidLoad() 23 24 } 25 }

・遷移先のビューコントローラー

Swift

1import UIKit 2 3class TopViewController: UIViewController{ 4 5 @IBOutlet weak var secondImageView: UIImageView! 6 @IBOutlet weak var secondLabel: UILabel! 7 8 9 10 override func viewDidLoad() { 11 12 super.viewDidLoad() 13 14 secondLabel.font = UIFont.boldSystemFont(ofSize: 40.0) 15 secondLabel.text = "Label" 16 secondLabel.textColor = .white 17 secondLabel.textAlignment = .center 18 19 } 20 21 @IBAction func backButton(_ sender: Any) { 22 23 dismiss(animated: true, completion: nil) 24 } 25}

・カスタムアニメーション用クラス

Swift

1import UIKit 2 3class LoginTransition: NSObject, UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning { 4 5 var isPresent: Bool = false 6 let duration : TimeInterval = 1 7 8 //画面遷移時の処理 9 func animationController(forPresented presented: UIViewController, 10 presenting: UIViewController, 11 source: UIViewController) -> UIViewControllerAnimatedTransitioning? 12 { 13 isPresent = true 14 return self 15 } 16 //画面に戻ってくる時の処理 17 func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 18 isPresent = false 19 return self 20 } 21 22 //アニメーションにかかる時間を設定する 23 func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 24 return duration 25 } 26 27 //遷移時のアニメーションを設定する 28 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 29 if isPresent { 30 animatePresentTransition(transitionContext: transitionContext) 31 } else { 32 animateDissmissalTransition(transitionContext: transitionContext) 33 } 34 } 35 36 //画面遷移時のアニメーションの内容を設定する 37 func animatePresentTransition(transitionContext: UIViewControllerContextTransitioning) { 38 39 /// 遷移元ビューコントローラー 40 let firstViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as! ViewController 41 /// 遷移先ビューコントローラー 42 let secondViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as! TopViewController 43 ///コンテナビュー 44 let containerView = transitionContext.containerView 45 46 ///コンテナビューにビューを登録する(遷移元の上に遷移先を乗せる) 47 containerView.insertSubview(secondViewController.view, belowSubview: firstViewController.view) 48 49 //遷移後のビューコントローラーを、予め最後の位置まで移動完了させ非表示にする 50 secondViewController.view.frame = transitionContext.finalFrame(for: secondViewController) 51 secondViewController.view.alpha = 0 52 //遷移後のイメージビューは、アニメーションが完了するまで非表示にする 53 secondViewController.secondImageView.isHidden = true 54 // 遷移元のイメージビューを非表示にする 55 firstViewController.firstImageView.isHidden = true 56 //遷移元のラベルを非表示にする 57 firstViewController.firstLabel.isHidden = true 58 //遷移先のラベルを非表示にする 59 secondViewController.secondLabel.isHidden = true 60 61 //アニメーションさせるラベルを作成する 62 let animationLabel = UILabel() 63 animationLabel.frame = secondViewController.secondLabel.frame.offsetBy(dx: 0, dy: 50) 64 animationLabel.font = UIFont.boldSystemFont(ofSize: 40.0) 65 animationLabel.text = "Label" 66 animationLabel.textColor = .white 67 animationLabel.textAlignment = .center 68 //遷移コンテナに、アニメーション用のラベルを追加する 69 containerView.addSubview(animationLabel) 70 71 // 遷移元のセルのイメージビューからアニメーション用のイメージビューを作成 72 let animationView = UIImageView(image: firstViewController.firstImageView.image) 73 //アニメーションビューの開始位置を指定する 74 //対象のイメージのframeからxとyがどれだけずれているかで位置を決める(0,0なら同じ位置ということなので開始位置になる) 75 animationView.frame = firstViewController.firstImageView.frame.offsetBy(dx: 0, dy: 0) 76 77 //遷移コンテナに、アニメーション用のイメージビューを追加する 78 containerView.addSubview(animationView) 79 80 //アニメーションを実装する(引数に秒数・アニメーションのクロージャ・完了後のクロージャを設定する) 81 UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { 82 83 // 遷移後のビューを徐々に表示する 84 secondViewController.view.alpha = 1.0 85 animationView.alpha = 0.3 86 //アニメーション用のビューを、遷移後のイメージの位置・サイズ(xとyが0,0なら同じ位置という事になる)までアニメーションする 87 animationView.frame = secondViewController.secondImageView.frame.offsetBy(dx:0, dy:0) 88 //アニメーション用のラベルを遷移後の位置までアニメーションする 89 animationLabel.frame = secondViewController.secondLabel.frame.offsetBy(dx:0, dy:0) 90 91 }, completion: { 92 //アニメーションが終了した後のクロージャ 93 finished in 94 // 遷移後のイメージを表示する 95 secondViewController.secondImageView.isHidden = false 96 // 遷移前のイメージビューの非表示を元に戻す 97 firstViewController.firstImageView.isHidden = false 98 //遷移元のラベルの非表示を元に戻す 99 firstViewController.firstLabel.isHidden = false 100 //遷移先のラベルの非表示を戻す 101 secondViewController.secondLabel.isHidden = false 102 // アニメーション用のビューを削除する 103 animationView.removeFromSuperview() 104 animationLabel.removeFromSuperview() 105 transitionContext.completeTransition(true) 106 }) 107 } 108 109 110 111 112 // 復帰時の処理 113 func animateDissmissalTransition(transitionContext: UIViewControllerContextTransitioning) { 114 115 /// 遷移元ビューコントローラー 116 let firstViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as! TopViewController 117 /// 遷移先ビューコントローラー 118 let secondViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as! ViewController 119 ///コンテナビュー 120 let containerView = transitionContext.containerView 121 122 ///コンテナビューにビューを登録する(遷移元の上に遷移先を乗せる) 123 containerView.insertSubview(firstViewController.view, belowSubview: secondViewController.view) 124 125 //遷移後のビューコントローラーにある移動すべきimageViewを、予め最後の位置まで移動完了させ非表示にする 126 secondViewController.view.frame = transitionContext.finalFrame(for: secondViewController) 127 secondViewController.view.alpha = 0 128 //遷移後のimageは、アニメーションが完了するまで非表示にする 129 secondViewController.firstImageView.isHidden = true 130 // 遷移元のイメージビューを非表示にする 131 firstViewController.secondImageView.isHidden = true 132 133 // 遷移元のセルのイメージビューからアニメーション用のイメージビューを作成 134 let animationView = UIImageView(image: firstViewController.secondImageView.image) 135 //アニメーションビューの開始位置を指定する 136 //対象のイメージのframeからxとyがどれだけずれているかで位置を決める(0,0なら同じ位置ということなので開始位置になる) 137 animationView.frame = firstViewController.secondImageView.frame.offsetBy(dx: 0, dy: 0) 138 139 //遷移コンテナに、アニメーション用のイメージビューを追加する 140 containerView.addSubview(animationView) 141 142 //アニメーションを実装する(引数に秒数・アニメーションのクロージャ・完了後のクロージャを設定する) 143 UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { 144 145 // 遷移後のビューを徐々に表示する 146 secondViewController.view.alpha = 1.0 147 animationView.alpha = 0.3 148 //アニメーション用のビューを、遷移後のイメージの位置・サイズ(xとyが0,0なら同じ位置という事になる)までアニメーションする 149 animationView.frame = secondViewController.firstImageView.frame.offsetBy(dx:0, dy:0) 150 }, completion: { 151 //アニメーションが終了した後のクロージャ 152 finished in 153 // 遷移後のイメージを表示する 154 secondViewController.firstImageView.isHidden = false 155 // 遷移前のイメージビューの非表示を元に戻す 156 firstViewController.secondImageView.isHidden = false 157 158 // アニメーション用のビューを削除する 159 animationView.removeFromSuperview() 160 transitionContext.completeTransition(true) 161 }) 162 } 163} 164

イメージ説明
イメージ説明

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

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

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

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

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

guest

回答1

0

ベストアンサー

イメージ説明

参考にでも

swift

1 // 遷移時の処理 2 func animatePresentTransition(transitionContext: UIViewControllerContextTransitioning) { 3 // 遷移元、遷移先、枠、アニメーション用のラベル画像を取得 4 let green = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as! GreenVC 5 let orange = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as! OrangeVC 6 let container: UIView! = transitionContext.containerView 7 8 let animationLabelImageView = UIImageView(image: green.label.getImage()) 9 10 // アニーメーションラベルの遷移元座標、遷移先座標を取得 11 let fromFrame = container.convert(green.label.frame, from: green.view) 12 let toFrame = container.convert(orange.label.frame, from: orange.view) 13 14 // アニメーションラベルに遷移元座標を設定する 15 animationLabelImageView.frame = fromFrame 16 17 // 遷移先を用意する 18 orange.view.frame = container.frame 19 orange.view.alpha = .zero 20 21 // 描画する 22 container.addSubview(orange.view) 23 container.addSubview(animationLabelImageView) 24 25 // 実在するラベルの設定 26 orange.label.isHidden = true 27 green.label.isHidden = true 28 29 // アニメーションしながら遷移元と遷移先を入れ替える 30 UIView.animate(withDuration: duration, animations: { 31 orange.view.alpha = 1.0 32 animationLabelImageView.frame = toFrame 33 34 }, completion: {_ in 35 orange.label.isHidden = false 36 green.removeFromParent() 37 animationLabelImageView.removeFromSuperview() 38 transitionContext.completeTransition(true) 39 }) 40 } 41 42 43extension UIView { 44 45 func getImage() -> UIImage{ 46 47 let rect = self.bounds 48 49 UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0) 50 let context: CGContext = UIGraphicsGetCurrentContext()! 51 52 self.layer.render(in: context) 53 54 let capturedImage : UIImage = UIGraphicsGetImageFromCurrentImageContext()! 55 56 UIGraphicsEndImageContext() 57 58 return capturedImage 59 } 60}

投稿2020/05/18 13:03

編集2020/05/18 13:13
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Ka_ya_

2020/05/18 14:02

tyobigorouさん、たびたびすみません。 丁寧にご回答下さりありがとうございます^^ アニメーション用のパーツをいくつも作るのは大変だなぁと思っていたので、 こういった方法があるのに感動しました…!! コメントも記載していただいて処理の意味が分かりやすく、 初心者の私にはとても助かります。 何度もお手数をおかけしてすみません、本当にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問