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

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

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

1244閲覧

ハンバーガメニュー遷移後もNavigationControllerを引き継いだままにしたい

kaz11

総合スコア10

iOS

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

Xcode

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

Swift

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

1グッド

1クリップ

投稿2020/07/29 08:27

編集2020/07/30 03:17

前提・実現したいこと

ハンバーガメニューに遷移後もNavigationControllerを引き継いだままにしたい

【!!質問を読まれる前に、まずこちらに目を通して頂けると幸いです!!】
結論から申し上げますと、こちらズレている質問をしておりますのでご回答いただく際には修正依頼の欄の連絡のやりとりをご覧いただけるとお時間を取らずに済むかと思われます。
ご指摘により、質問自体がズレているものであることに気付きました。私のほうで一度UIの設計から検討し直したいと思います。自身で解決(?)できた際に、実行した旨を追記していこうと思います。
なお、UIの設計等でご指摘やアドバイスありましたら大変助かりますので回答いただいても全く問題ございません。
失礼致しました。

2020/07/30
質問の最下部の補足を更新しました。

はじめまして。
iOS開発を始めて2ヶ月になる者です。
現在、転職活動のためのポートフォリを作成しております。

BaseViewControllerからSetUpViewController(ハンバーガメニュー)へ遷移させる際にNavigationControllerを引き継ぐことができず、困っております。
※ページの始まりにNavigationControllerを置いています。

BaseViewControllerの左横から被さる形でSetUpViewControllerをハンバーガーメニューとして表示してます。SetUpViewControllerにはkeychainAccessという外部ライブラリを用いて、一度ユーザー登録していただいた方のプロフィール画像とユーザー名を取得できるようにしております。アイコンボタンをタップすることで、ユーザー登録していただいたユーザーの方は、プロフィール画面(accountViewController)に遷移できる仕様にしております。
SetUpViewControllerにNavigationControllerを継承させないと、プロフィール画面(accountViewController)に遷移できない仕様になっております。
※なお、keychainAccessは自分で設定しておいたkeyに値を保持しておけるライブラリです。(間違ってたらすみません。)

説明わかりづらくて大変申し訳ありませんが、ご回答いただけると幸いです。
質問の後半に画面の遷移図を画像で載せておきました。
version
・Xcode 11.5
・Swift 5.2.4

以下、ソースになります。

ソースコード

swift

1BaseViewController.swift 2 3import UIKit 4import SegementSlide 5 6class BaseViewController:SegementSlideDefaultViewController { 7 8 9 override func viewDidLoad() { 10 super.viewDidLoad() 11 12 } 13 14 override func viewWillAppear(_ animated: Bool) { 15 super.viewWillAppear(animated) 16 navigationController?.isNavigationBarHidden = false 17 } 18 19 //SetUpViewControllerを表示させるアクション 20 @IBAction func set(_ sender: Any) { 21 22   let setUpVC = self.storyboard?.instantiateViewController(withIdentifier: "setUp") as! SetUpViewController 23  self.navigationController?.present(setUpVC, animated: true) 24 25 } 26}

swift

1SetUpViewController.swift 2 3import UIKit 4import Firebase 5import KeychainAccess 6import SDWebImage 7 8class SetUpViewController: UIViewController, UIGestureRecognizerDelegate { 9 10 11 @IBOutlet weak var channelTapRecognizer: UIButton! 12 @IBOutlet var IconTapRecognizer: UITapGestureRecognizer! 13 @IBOutlet weak var profileIcon: UIImageView! 14 @IBOutlet weak var userNameLabel: UILabel! 15 @IBOutlet weak var menuView: UIView! 16 17 18 override func viewDidLoad() { 19 super.viewDidLoad() 20 21 22 let IconTapRecognizer:UITapGestureRecognizer = UITapGestureRecognizer( 23 target: self, 24 action: #selector(SetUpViewController.tapped(_:))) 25 26 IconTapRecognizer.delegate = self 27 self.view.addGestureRecognizer(IconTapRecognizer) 28 29 } 30 31 override func viewWillAppear(_ animated: Bool) { 32 super.viewWillAppear(animated) 33 34 navigationController?.isNavigationBarHidden = false 35 36 //ハンバーガーメニューのアニメーション設定 37 let menuPosition = self.menuView.layer.position 38 self.menuView.layer.position.x = -self.menuView.frame.width 39 UIView.animate( 40 withDuration: 0.1, 41 delay: 0.1, 42 options: .curveEaseOut, 43 animations: { 44 self.menuView.layer.position.x = menuPosition.x 45 }, 46 completion: { bool in 47 }) 48 } 49 50 //ハンバーガメニューで表示されたページの外をタップすると、ハンバーガメニューが閉じるアクション 51 override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { 52 super.touchesEnded(touches, with: event) 53 for touch in touches { 54 if touch.view?.tag == 1 { 55 UIView.animate( 56 withDuration: 0.2, 57 delay: 0, 58 options: .curveEaseIn, 59 animations: { 60 self.menuView.layer.position.x = -self.menuView.frame.width 61 }, 62 completion: { bool in 63 self.dismiss(animated: true, completion: nil) 64 } 65 ) 66 } 67 } 68 } 69 70 //アイコンボタンタップアクション 71 //一度ユーザー登録していればaccountViewControllerページに遷移します 72 //ユーザー登録されていなければ、LoginViewControllerページに遷移します 73 @objc func tapped(_ sender: UITapGestureRecognizer){ 74 if sender.state == .ended { 75       76 if Auth.auth().currentUser?.uid != nil { 77 let accountVC = self.storyboard?.instantiateViewController(withIdentifier: "account") as! accountViewController 78 let keychain = Keychain(service: "XXXXXXXXXXX") 79 let fbUserName = keychain["XXXX"] 80 let fbUserPicture = keychain["XXXX"] 81 let twitterUserName = keychain["XXXX"] 82 let twitterUserPicture = keychain["XXXX"] 83 let emailUserName = keychain["XXXX"] 84 let emailUserPicture = keychain["XXXX"] 85 if fbUserName != nil || fbUserPicture != nil { 86 accountVC.userName = fbUserName! 87 accountVC.profileImage = fbUserPicture! 88 self.navigationController?.pushViewController(accountVC, animated: true) 89 }else if twitterUserName != nil || twitterUserPicture != nil { 90 accountVC.userName = twitterUserName! 91 accountVC.profileImage = twitterUserPicture! 92 self.navigationController?.pushViewController(accountVC, animated: true) 93 }else if emailUserName != nil || emailUserPicture != nil{ 94 accountVC.userName = emailUserName! 95 accountVC.profileImage = emailUserPicture! 96 self.navigationController?.pushViewController(accountVC, animated: true) 97 } else { 98 let loginVC = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginViewController 99 self.navigationController?.pushViewController(loginVC, animated: true) 100 } 101 } 102 103 } 104 else if sender.state == .began { 105 106 } 107 } 108} 109 110

試したこと

BaseViewControllerにて、以下のコードを書くとNavigationControllerを継承できることはわかりましたが、今度はハンバーガメニューが左横から覆いかぶさるように出現せず、SetUpViewControllerが独立したページとして表示されます。

swift

1let setUpVC = self.storyboard?.instantiateViewController(withIdentifier: "setUp") as! SetUpViewController 2self.navigationController?.pushViewController(setUpVC, animated: true)

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

文字だけだとわかりづらいと思ったので、図にしました。
イメージ説明

その他もろもろ調べたのですが、解決できませんでした。
説明わかりづらくて大変申し訳ありませんが、ご回答いただけると幸いです。
長文失礼致しました。

【補足】
下記のURLを参考に作成しました。
http://swift.hiros-dot.net/?p=377
また、修正依頼にすでに記載済みではあるのですが、ご指摘いただいた通りハンバーガーメニューを出すことと Navigation Controller の利用は本質的に無関係みたいですのでもう少し自分で調べて解決していこうと思います。
お手数おかけします。

TsukubaDepot👍を押しています

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

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

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

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

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

thyda.eiqau

2020/07/29 23:00

NavigationControllerにpushさせたいから、SetUpViewControllerが大元のNavigationControllerにアクセスできるようにしたいという意味ですか? 「継承」というと別の意味で広く使われているので紛らわしいですが……
thyda.eiqau

2020/07/29 23:05

あと、アイコンボタンをタップした時点ではNavigationControllerの上にSetUpViewControllerがいるので、NavigationControllerにpushViewControllerしたところでSetUpViewControllerがその上に被さっているから遷移したことがわからない(蓋されていて見えない)と思うんですが、それはいいんでしょうか?
TsukubaDepot

2020/07/30 01:50

検索していたら http://swift.hiros-dot.net/?p=377 上記のサイトで提示されたコードとかなり似ているコードを発見したのですが、こちらを参考にされていますでしょうか。 記事内では Navigation Controller を使っていますが、ハンバーガーメニューを出すことと Navigation Controller の利用は本質的に無関係なので、もし混同されているのであれば切り分ける必要があるかと思います ちなみに、同じような(というかコードはほぼそのままの)記事で Qiita の記事も見つけましたが、そちらは Navigation Controller は使っていません。 https://qiita.com/takehiro224/items/dc5903ae42f288ccd5f7 (記事の作成日を見ると、Qiitaが先で、swift.hiros-dot.netの記事が半年くらい後ですね)
kaz11

2020/07/30 02:16

thyda.eiqau様 修正依頼ありがとうございます。 >>SetUpViewControllerが大元のNavigationControllerにアクセスできるようにしたいという意味ですか? →左様でございます。NavigationControllerにアクセスできるようにしたいという意味です。また、「継承」の使い方間違っていて申し訳ありません。 >>NavigationControllerにpushViewControllerしたところでSetUpViewControllerがその上に被さっているから遷移したことがわからない →こちらは私は特に問題ないと思っております。もし、「いや、それは問題では?」と思われるところがあれば理由と共にご指摘いただけると幸いです。 ※わたくしの学習不足で、「遷移したことがわからない」という内容の問題点がよく理解できておりません。
kaz11

2020/07/30 02:22

TsukudaDepot様 修正依頼ありがとうございます。 >>http://swift.hiros-dot.net/?p=377 >>上記のサイトで提示されたコードとかなり似ているコードを発見したのですが、こちらを参考にされてい>>ますでしょうか。 →上記のURLを参考に作成致しました。記載が足らず、お手数おかけしました。 >>ハンバーガーメニューを出すことと Navigation Controller の利用は本質的に無関係なので、もし混同されているのであれば切り分ける必要がある →なるほど。完全に混同しておりました。無関係である場合、わたくしの質問自体ズレたものになりますね。ご指摘ありがとうございます。お手数おかけして申し訳ありません。 また、Qitta記事のURL添付ありがとうございます。もっと調べて、解決に努めてみます。
TsukubaDepot

2020/07/30 02:32

Qiita記事の方は、画面に表示されたボタンを押すとメニューがスライドして出てくるようになっています。 したがって、メニューを出すためにNavigationControllerを使う必要はないと思います。 一方、Base, Login, Account の各ViewControllerをNavigationControllerの管理下において遷移させるのであれば、ハンバーガーメニューとして表示するSetUpViewControllerの表示方法や、SetUpViewControllerからAccountに移動させる方法などについては少し慎重に検討する必要がありそうに感じます。そもそも、ログインの処理を前後の行き来が可能なNavigationControllerで実装する必要があるのかも一考の余地はあるとおもいますで(ログイン後にログイン前の画面に戻る必要はない、など)、参考にしていただければと思います。
kaz11

2020/07/30 02:59

TsukudaDepot様 追加でのご説明ありがとうございます。 >>Base, Login, Account の各ViewControllerをNavigationControllerの管理下において遷移させるのであれば、ハンバーガーメニューとして表示するSetUpViewControllerの表示方法や、SetUpViewControllerからAccountに移動させる方法などについては少し慎重に検討する必要がある →まったくおしゃっられている通りだと思いました。UIを検討し直してみます。丁寧なご説明ありがとうございました。
guest

回答2

0

提示されたコードをそのままコピペして実行しても思った画面にならないので、おそらく必要な箇所が省略されているのだと思います。ので動作まで確認できていませんが方針だけ回答できればと思います。

例えば、次のようなプロトコルをNavigationControllerに仕込んでおいて、認証に関する画面遷移はNavigationControllerにまかせてしまいます。

swift

1protocol AuthNavigationDelegate { 2 func showLogInViewController() -> Void 3 func showAccountViewController(userName: String?, profieImage: String?) -> Void 4} 5 6class RootNavigationController: UINavigationController, AuthNavigationDelegate { 7 func showLogInViewController() { 8 let loginVC = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginViewController 9 self.pushViewController(loginVC, animated: true) 10 } 11 12 func showAccountViewController(userName: String?, profieImage: String?) { 13 let accountVC = self.storyboard?.instantiateViewController(withIdentifier: "account") as! accountViewController 14 accountVC.userName = userName 15 accountVC.profileImage = profieImage 16 self.pushViewController(accountVC, animated: true) 17 } 18}

BaseViewControllerからSetUpViewControllerを呼び出すときに、このdelegateを渡してしまえばよいです。

swift

1class BaseViewController: SegementSlideDefaultViewController { 2 // 省略 3 4 //SetUpViewControllerを表示させるアクション 5 @IBAction func set(_ sender: Any) { 6 let setUpVC = self.storyboard?.instantiateViewController(withIdentifier: "setUp") as! SetUpViewController 7 setUpVC.authNavigationDelegate = self.navigationController as! RootNavigationController 8 self.present(setUpVC, animated: true) 9 } 10} 11 12class SetUpViewController: UIViewController, UIGestureRecognizerDelegate { 13 var authNavigationDelegate: AuthNavigationDelegate? 14 15 // 省略 16 17 //アイコンボタンタップアクション 18 //一度ユーザー登録していればaccountViewControllerページに遷移します 19 //ユーザー登録されていなければ、LoginViewControllerページに遷移します 20 @objc func tapped(_ sender: UITapGestureRecognizer){ 21 if sender.state == .ended { 22 if Auth.auth().currentUser?.uid != nil { 23 let keychain = Keychain(service: "XXXXXXXXXXX") 24 25 let fbUserName = keychain["XXXX"] 26 let fbUserPicture = keychain["XXXX"] 27 if fbUserName != nil || fbUserPicture != nil { 28 self.authNavigationDelegate?.showAccountViewController(userName: fbUserName, profieImage: fbUserPicture) 29 return 30 } 31 32 let twitterUserName = keychain["XXXX"] 33 let twitterUserPicture = keychain["XXXX"] 34 if twitterUserName != nil || twitterUserPicture != nil { 35 self.authNavigationDelegate?.showAccountViewController(userName: twitterUserName, profieImage: twitterUserPicture) 36 return 37 } 38 39 let emailUserName = keychain["XXXX"] 40 let emailUserPicture = keychain["XXXX"] 41 if emailUserName != nil || emailUserPicture != nil { 42 self.authNavigationDelegate?.showAccountViewController(userName: emailUserName, profieImage: emailUserPicture) 43 return 44 } 45 46 self.authNavigationDelegate?.showLogInViewController() 47 } 48 } 49 else if sender.state == .began { 50 } 51 } 52}

投稿2020/07/31 02:25

thyda.eiqau

総合スコア2982

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

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

kaz11

2020/07/31 04:30

thyda.eiqau様 ご回答ありがとうございます。大変勉強になります、ありがとうございます。 さっそく試しに記述してみました! >>NavigationControllerにまかせてしまう →RootNavigationController.swiftファイルを作成し、プロトコル(protocol AuthNavigationDelegate ~ )を記述し、NavigationControllerに結びつけました。ここまでで手順が間違っていたら大変申し訳ありません。NavigationControllerにコードを記述したことがなく、おそらくこの方法で合ってると思い、試してみました。 結論から申し上げますと、うまくいきませんでした。 詳しく申し上げますと、BaseViewControllerからSetUpViewControllerへの遷移は問題ないのですが、SetUpViewControllerからLoginViewControllerおよびAccountViewControllerへの遷移ができませんでした。 おそらくBaseViewContrllerで”self.present(setUpVC, animated: true)”のように"present"で遷移するとSetUpViewControllerでNavigationControllerのプロトコルを引き継がないのではないかと推測しました。以下、推測の根拠です。 LoginViewControllerへのsegueにIDを持たせて、SetUpViewControllerにてperformSegue(withIdentifier: "login", sender: nil)と記載したところ遷移しました。 お時間割いていただきありがとうございました。自分でプロトコルを記述する技術までしっかりもっていけていないので感動しました。時間をかけてコードを読みました。これでダメならUIそのものを変えるか、いったん置いておいて必要な機能の実装を先に片付けてしまおうと思います。高評価をつけさせていただきます。本当にありがとうございました。
thyda.eiqau

2020/07/31 07:38

> BaseViewContrllerで”self.present(setUpVC, animated: true)”のように"present"で遷移するとSetUpViewControllerでNavigationControllerのプロトコルを引き継がない SetUpViewControllerで self.navigationController でアクセスすることができない、という意味なら、そのとおりです。なので、 setUpVC.authNavigationDelegate = self.navigationController as! RootNavigationController の行でsetUpVCのプロパティとしてNavigationControllerを渡しています。そのうえでSetUpViewController側では self.authNavigationDelegate?.showLogInViewController() のように、プロパティとして保持しているNavigationControllerにアクセスしています。 ところで追記・修正依頼の欄にも書きましたが、NavigationControllerにどれだけpushさせたとしても、そのうえにSetUpViewControllerがpresentされているのですから、目には見えませんよ。ビューヒエラルキーは確認しましたか? https://qiita.com/akatsuki174/items/45d4bd7cb150defbf116
kaz11

2020/07/31 17:36

thyda.eiqau様 追加のご説明ありがとうございます。また、ビューヒエラルキーに関するURLの添付ありがとうございます。 >> ビューヒエラルキーは確認しましたか? →すみません。ビューヒエラルキーという単語を初めて聞きました。さっそくビューヒエラルキーを確認してみました。 さっそく確認しましたところ、BaseViewControllerからpresentした場合とpushさせた場合で表示されるビューヒエラルキーが違いました。 ・presentさせた場合(setUpVCにプロパティとしてNavigationControllerを渡している場合も含む) →RootViewController, BaseViewController, SetUpViewControllerの順でビューヒエラルキーが表示されました。 ・pushした場合 →RootViewController, SetUpViewControllerの順でビューヒエラルキーが表示されました。 RootViewController上にSetUpViewControllerが表示されている場合は、予測通りの画面遷移をするので、 >>SetUpViewControllerがpresentされているのですから、目には見えませんよ →上記でおっしゃりたいことは、NavigationControllerにSetUpViewControllerをpushさせたとしてもビューヒエラルキーの表示ではBaseViewControllerが目に言えないから、それは大丈夫なのか?ということなのかなと思いました。間違ってたらすみません。 もし上記のご指摘であるならば、おっしゃられている通りなのでUIを考え直そうと思っております。 SetUpViewControllerが画面いっぱいに表示されているため、ハンバーガーメニューになっているかわからないのではないか?というご指摘でしたら、以下のURLを参考にViewのOpacityを50%にしているためpresentの呼び出し元であるBaseViewControllerは背景に見えてはおります。 http://swift.hiros-dot.net/?p=377 画像通りの動きをするのは、 BaseViewControllerからSetUpViewControllerにpushで遷移させ、かつSetUpViewControllerからLoginViewController、AccountViewControllerにpushで遷移する場合のみでした。(thyda.eiqau様のコードをもってしても予想通りの動きは実現できませんでした) ※なお、pushのみで遷移する場合、SetUpViewControllerがBaseViewControllerの上に完全に被せるため、ハンバーガメニューとして表示されてるとは言えない状態です。 ハンバーガメニューにそこまでこだわる必要もないため、UIを設計し直すのがベストだと考えました。 thyda.eiqau様、コード考えてくださりありがとうございました。NavigationControllerにコードを記述するという発想やビューヒエラルキーなど色々学ばせていただきました。 今回は自分でUIを設計し直すという形で締め括りたいと思います。ご丁寧な回答ありがとうございました。
guest

0

自己解決

自己解決しました!
色々試行錯誤した末にUIの画面の遷移の方法を根本から変更しました。
解決したというよりかはStoryboard内の設計を変えました。
まずLoginViewContorllerをアプリケーション起動時の最初の画面に持っていきました。Loginが完了した後にTab Bar Controllerで大まかな機能ごとに画面遷移させました。
SetUpViewControllerとAccountViewControllerページは消しました。会員情報等のデータを入力してユーザーのプロフィールを記入する必要がないサービスだと思ったのでAccountViewControllerは消しました。(ログイン機能は匿名ログイン機能を実装)
以下がイメージ画像となります。
イメージ説明

回答に協力していただいた方々ありがとうございました。大変時間がかかり、大幅な仕様の変更がありつつも何とか形になりつつあります。
この調子でリリースまで進み、転職活動に挑みたいです。

投稿2020/09/30 02:06

編集2020/09/30 02:10
kaz11

総合スコア10

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問