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

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

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

0回答

959閲覧

上部タブを用いたアプリでの画面遷移が実現できない

ken1231

総合スコア5

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/04/01 15:35

iOSアプリを個人で開発しているプログラミング初心者です。

ライブラリを用いて、画面上部に左右にスワイプすることで画面が遷移するタブを設けています。
HomeViewControllerの上にFirstViewController、SecondViewControllerを配置し、それが左右スワイプによって切り替えられるようになっています。
FirstViewController上にCollectionViewを配置し、そのセルをタップすることでDetailViewControllerに遷移したいのですが、DetailViewControllerから元のFirstViewControllerに戻る動作がうまく実現できません。具体的には、戻る際の右スワイプがタブ切替のスワイプ動作と競合してしまい、思うようなアニメーション(PinterestやTwitterの検索画面のようなイメージです)ができません。

使用言語はSwift5
主な使用ライブラリはSwipeMenuViewControllerです

以下に試してみたこととソースコードを記載しております。
うまく画面遷移を実現することができるような方法があればご教授願います。
足りない情報などがあれば補足いたしますので、ご指摘いただけると幸いです。

1 NavigationControllerを用いて画面遷移

HomeViewControllerからUINavigationController(rootViewController: FirstViewController())を呼び出し、DetailViewControllerへも普通にpushを用いた画面遷移で移動する

問題点
NavigationControllerの戻る動作(右スワイプ)と上部タブのスワイプ動作が競合してしまい、右にスワイプしてもタブを移動するだけになってしまう(戻るボタンは機能する)

2 FirstViewControllerからの遷移の際にHomeViewControllerのviewDidLoadを呼び出すことでDetailViewControllerを無理やり一番上に被せる

HomeViewController

1import UIKit 2import SwipeMenuViewController 3 4class HomeViewController: SwipeMenuViewController { 5 enum ViewType { 6 case home 7 case first 8 init() { 9 self = ViewType.home 10 } 11 } 12 13 static var viewType = ViewType() 14 15 override func viewDidLoad() { 16 switch HomeViewController.viewType { 17 case .home: 18 addChildren() 19 super.viewDidLoad() 20 case .first: 21 showDetailViewController() 22 } 23 24 //DetailViewControllerをHomeViewControllerの上に無理やり被せることでタブの左右スワイプの影響を受けないようにしています 25 private func showDetailViewController() { 26 let vc = DetailViewController() 27 UIView.transition(with: view, duration: 0.3, options: .transitionFlipFromRight, animations: { 28 self.addChild(vc) 29 self.view.addSubview(vc.view) 30 vc.didMove(toParent: self) 31 }, completion: nil) 32 } 33 34 private func addChildren() { 35 addChild(FirstViewController()) 36 addChild(SecondViewController()) 37 } 38 39 // MARK: - SwipeMenuViewDelegate 40 (特にいじっていません) 41 42 // MARK: - SwipeMenuViewDataSource 43 override func numberOfPages(in swipeMenuView: SwipeMenuView) -> Int { 44 return children.count 45 } 46 47 override func swipeMenuView(_ swipeMenuView: SwipeMenuView, titleForPageAt index: Int) -> String { 48 return children[index].title ?? "" 49 } 50 51 override func swipeMenuView(_ swipeMenuView: SwipeMenuView, viewControllerForPageAt index: Int) -> UIViewController { 52 let vc = children[index] 53 vc.didMove(toParent: self) 54 return vc 55 } 56} 57

FirstViewController

1import UIKit 2 3class FirstViewController: UIViewController { 4 5 override func viewDidLoad() { 6 super.viewDidLoad() 7 title = "FIRST" 8 collectionView.delegate = self 9 collectionView.dataSource = self 10 view.addSubview(collectionView) 11 } 12} 13 14extension FirstViewController: UICollectionViewDataSource { 15 func numberOfSections(in collectionView: UICollectionView) -> Int { 16 return 1 17 } 18 19 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 20 return 20 21 } 22 23 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 24 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! BaseCollectionViewCell 25 return cell 26 } 27} 28 29extension FirstViewController: UICollectionViewDelegate { 30 //DetailViewControllerへの画面遷移時に無理やりHomeViewController(parent)のviewDidLoadを呼び出しています 31 func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 32 HomeViewController.viewType = .first 33 parent!.viewDidLoad() 34 } 35} 36 37extension FirstViewController: UICollectionViewDelegateFlowLayout { 38 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 39 return CGSize(width: 20, height: 20) 40 } 41} 42

DetailViewController

1import UIKit 2class DetailViewController: UIViewController { 3 4 private var viewAnimator = UIViewPropertyAnimator() 5 private var animationProgress: CGFloat = 0.0 6 7 override func viewDidLoad() { 8 super.viewDidLoad() 9 setupAnimator() 10 11 let recognizer = UIPanGestureRecognizer() 12 recognizer.addTarget(self, action: #selector(viewPanned(recognizer:))) 13 view.addGestureRecognizer(recognizer) 14 15 view.backgroundColor = .white 16 } 17 18 private func setupAnimator() { 19 viewAnimator = UIViewPropertyAnimator(duration: 0.5, curve: .linear) { 20 self.view.frame = CGRect(~) //画面をそのままの大きさで右に移した位置を指定しています 21 self.view.layoutIfNeeded() 22 } 23 viewAnimator.pausesOnCompletion = true 24 viewAnimator.addCompletion { _ in 25 self.willMove(toParent: nil) 26 self.view.removeFromSuperview() 27 self.removeFromParent() 28 } 29 } 30 31 //右にスワイプすることでDetailViewControllerが画面外(右側)に移動します 32 @objc private func viewPanned(recognizer: UIPanGestureRecognizer) { 33 switch recognizer.state { 34 case .began: 35 viewAnimator.pauseAnimation() 36 animationProgress = viewAnimator.fractionComplete 37 case .changed: 38 let x = recognizer.translation(in: view).x 39 var fraction = x / UIScreen.main.bounds.size.width 40 if viewAnimator.isReversed { fraction *= -1 } 41 viewAnimator.fractionComplete = fraction + animationProgress 42 case .ended: 43 let x = recognizer.velocity(in: view).x 44 if x == 0 { 45 viewAnimator.continueAnimation(withTimingParameters: nil, durationFactor: 0) 46 return 47 } 48 viewAnimator.isReversed = (x < 0) 49 viewAnimator.continueAnimation(withTimingParameters: nil, durationFactor: 0) 50 default: () 51 } 52 } 53 54}

問題点
表面上はやりたい動きが実現できていますが、右にスワイプしたDetailViewControllerを削除することができず(completionが動作しない)、DetailViewControllerを右にスワイプしてFirstViewControllerに戻る度にDetailViewControllerが画面外に溜まっていき、無駄なメモリを消費してしまう

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

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

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

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問