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

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

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

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

Swift

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

iPhone

iPhoneとは、アップル社が開発・販売しているスマートフォンです。 同社のデジタルオーディオプレーヤーiPodの機能、電話機能、インターネットやメールなどのWeb通信機能の3つをドッキングした機器です。

Q&A

解決済

1回答

754閲覧

「ボタン」でタップするとフォトライブラリが開くようにしたいです。

magiee

総合スコア28

Xcode

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

Swift

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

iPhone

iPhoneとは、アップル社が開発・販売しているスマートフォンです。 同社のデジタルオーディオプレーヤーiPodの機能、電話機能、インターネットやメールなどのWeb通信機能の3つをドッキングした機器です。

0グッド

0クリップ

投稿2020/05/06 07:38

現状のswiftの動き

①アイコンをタップすると遷移先のControllerから、フォトライブラリが開く。
②画像を選択すると、遷移前のUIImageViewにセットされる。

実現したいこと

アイコンをタップすると自動的にフォトライブラリが開くのではなく、
遷移前にあるボタンを押すことで、フォトライブラリが開くようにしたいです。

ご教授のほど、よろしくお願い致します。

storybord

イメージ説明

該当のソースコード

import UIKit class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate { var myImagePicker: UIImagePickerController! var myImageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() self.title = "Select a Image" myImageView = UIImageView(frame: self.view.bounds) // インスタンス生成 myImagePicker = UIImagePickerController() // デリゲート設定 myImagePicker.delegate = self // 画像の取得先はフォトライブラリ myImagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary // 画像取得後の編集を不可に myImagePicker.allowsEditing = false } override func viewDidAppear(_ animated: Bool) { self.present(myImagePicker, animated: true, completion: nil) } /** 画像が選択された時に呼ばれる. */ func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { //選択された画像を取得. let myImage: AnyObject? = info[UIImagePickerController.InfoKey.originalImage] as AnyObject //選択された画像を表示するViewControllerを生成. let secondViewController = SecondViewController() //選択された画像を表示するViewContorllerにセットする. secondViewController.mySelectedImage = myImage as? UIImage myImagePicker.pushViewController(secondViewController, animated: true) } /** 画像選択がキャンセルされた時に呼ばれる. */ func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { // モーダルビューを閉じる self.dismiss(animated: true, completion: nil) } }

画面遷移先のコード

import Foundation import UIKit class SecondViewController: UIViewController { var mySelectedImage: UIImage! var mySelectedImageView: UIImageView! override func viewDidLoad() { self.edgesForExtendedLayout = [] self.view.backgroundColor = UIColor.white setImage() } /** 選択された画像をUIImageViewにセットする. */ func setImage(){ self.title = "Selected Image" mySelectedImageView = UIImageView(frame: self.view.bounds) mySelectedImageView.contentMode = UIView.ContentMode.scaleAspectFit mySelectedImageView.image = mySelectedImage self.view.addSubview(mySelectedImageView) } }

使用している言語

swift
Xvode 11.4

ご教授のほど、よろしくお願い致します。

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

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

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

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

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

guest

回答1

0

ベストアンサー

質問者さんがおっしゃられる「アイコン」というのが、ホーム画面にあるアプリのアイコンのことと仮定しての回答ですが、

現状のswiftの動き

①アイコンをタップすると遷移先のControllerから、フォトライブラリが開く。
②画像を選択すると、遷移前のUIImageViewにセットされる。

ソースを拝見する限り、

  1. アプリを起動(アイコンをタップ)すると、最初のビューが開いた瞬間にフォトライブラリが開く
  2. 画像を選択すると、遷移後の画面に動的に配置した(コードで記述した)UIImageView に画像が表示される

という流れになっており、想定されている流れとは異なっているように思えます。

と言うのも、ViewControllerviewDidAppear

swift

1 override func viewDidAppear(_ animated: Bool) { 2 self.present(myImagePicker, animated: true, completion: nil) 3 4 }

を実行していますから、画面にビューが表示された瞬間、myImagePickerで指定されたビュー(つまり、イメージピッカーが表示されてしまいます。

また、イメージピッカーで画像を選択した後に呼び出される delegate

swift

1 画像が選択された時に呼ばれる. 2 */ 3 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { 4 5 //選択された画像を取得. 6 let myImage: AnyObject? = info[UIImagePickerController.InfoKey.originalImage] as AnyObject 7 8 //選択された画像を表示するViewControllerを生成. 9 let secondViewController = SecondViewController() 10 11 //選択された画像を表示するViewContorllerにセットする. 12 secondViewController.mySelectedImage = myImage as? UIImage 13 14 myImagePicker.pushViewController(secondViewController, animated: true) 15 16 }

という処理を行なっていますが、この中でpushViewControllerが呼び出されているため、画面が遷移してしまいます。

ボタンを押した時にイメージピッカーを開くのであれば、present(myImagePicker, animated: true, completion: nil)をボタンを押した時の処理の中に記述する必要がありますので、ご確認ください。


ViewController はこんな感じになります。
⑤については、オリジナルのコードのままで大丈夫です。

swift

1import UIKit 2 3class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate { 4 5 var myImagePicker: UIImagePickerController! 6 7 // MARK: 次の画面に移るための BarButtonItem 8 @IBOutlet weak var nextBarButtonItem: UIBarButtonItem! 9 10 // MARK: ③の遷移前の画面に表示するイメージビュー 11 @IBOutlet weak var sampleView: UIImageView! 12 13 // ①アイコンをタップするとviewControllerが開く 14 override func viewDidLoad() { 15 super.viewDidLoad() 16 17 self.title = "設定モード" 18 19 // MARK: 画像が選択されていないときには BarButtonItem を無効にする 20 nextBarButtonItem.isEnabled = false 21 } 22 23 //②「フォトライブラリを開く」ボタンを押すとフォトライブラリが起動する 24 @IBAction func photoLibraryButton(_ sender: Any) { 25 // インスタンス生成 26 myImagePicker = UIImagePickerController() 27 28 // デリゲート設定 29 myImagePicker.delegate = self 30 31 // 画像の取得先はフォトライブラリ 32 myImagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary 33 34 // 画像取得後の編集を不可に 35 myImagePicker.allowsEditing = false 36 37 // MARK: ここでイメージピッカーを表示させる 38 present(myImagePicker, animated: true, completion: nil) 39 } 40 41 /** 42 画像が選択された時に呼ばれる. 43 */ 44 // MARK: ③ライブラリが閉じると、遷移前のimageViewに表示される。 45 // ここでは、遷移前の画面に選択したイメージを表示した上、BarButtonItem を有効にするだけ 46 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { 47 48 // 選択された画像を取得 49 if let myImage = info[.originalImage] as? UIImage { 50 // 遷移前の画面に画像を表示する 51 sampleView.image = myImage 52 53 // BarButtonItem を有効にする 54 nextBarButtonItem.isEnabled = true 55 } 56 // イメージピッカーを消す 57 dismiss(animated: true, completion: nil) 58 } 59 60 /** 61 画像選択がキャンセルされた時に呼ばれる. 62 */ 63 func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { 64 // モーダルビューを閉じる 65 self.dismiss(animated: true, completion: nil) 66 } 67 68 // ④NavigationBarにある、BarButtonItemで、画面遷移を行う。 69 @IBAction func nextpages(_ sender: Any) { 70 // MARK: セグエを実行する。 71 performSegue(withIdentifier: "toNext", sender: nil) 72 } 73 74 // MARK: ④の続き。 75 // perfomSegue を実行すると、prepare が呼び出される。ここで値渡しを行う 76 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 77 // segue 名が "toNext" か判断する 78 if segue.identifier == "toNext" { 79 // segue の遷移先が SecondViewController の場合 80 if let nextVC = segue.destination as? SecondViewController { 81 // 遷移先のプロパティ(変数)に値をコピーする 82 nextVC.mySelectedImage = sampleView.image 83 } 84 } 85 } 86}

画面デザインはこんな感じです。

イメージ説明

投稿2020/05/06 10:36

編集2020/05/10 00:42
TsukubaDepot

総合スコア5086

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

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

magiee

2020/05/08 03:31

回答していただきありがとうございます。 ``` @IBAction func photoLibraryButton(_ sender: Any) {present(myImagePicker, animated: true, completion: nil) } ``` を追加して、```viewDidAppear```、 ```myImagePicker.pushViewController``` を削除しました。 しかし、今度は遷移後のUIImageView に画像が表示されなくなりました。 こちらは何が原因なのでしょうか? ``` import UIKit class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate { //中略 @IBAction func photoLibraryButton(_ sender: Any) { present(myImagePicker, animated: true, completion: nil) } /** 画像が選択された時に呼ばれる. */ func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { //選択された画像を取得. let myImage: AnyObject? = info[UIImagePickerController.InfoKey.originalImage] as AnyObject //選択された画像を表示するViewControllerを生成. let secondViewController = SecondViewController() //選択された画像を表示するViewContorllerにセットする. secondViewController.mySelectedImage = myImage as? UIImage // モーダルビューを閉じる self.dismiss(animated: true, completion: nil) } @IBAction func nextpages(_ sender: Any) { performSegue(withIdentifier: "nextPages", sender: nil) } /** 画像選択がキャンセルされた時に呼ばれる. */ func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { // モーダルビューを閉じる self.dismiss(animated: true, completion: nil) } } ``` 遷移後のコード ``` import Foundation import UIKit class SecondViewController: UIViewController { var mySelectedImage: UIImage! var mySelectedImageView: UIImageView! override func viewDidLoad() { self.edgesForExtendedLayout = [] self.view.backgroundColor = UIColor.white setImage() } /** 選択された画像をUIImageViewにセットする. */ func setImage(){ self.title = "Selected Image" mySelectedImageView = UIImageView(frame: self.view.bounds) mySelectedImageView.contentMode = UIView.ContentMode.scaleAspectFit mySelectedImageView.image = mySelectedImage self.view.addSubview(mySelectedImageView) } } ```
TsukubaDepot

2020/05/08 06:40

まずは、magieeさんがやりたいと思っていらっしゃる仕様を確認させてください。 質問では、 > 現状のswiftの動き > > ①アイコンをタップすると遷移先のControllerから、フォトライブラリが開く。 > ②画像を選択すると、遷移前のUIImageViewにセットされる。 となっています。しかし、質問時のコードには画面遷移のためのコードも含まれていました。 なので、選択した画像は画面遷移後に表示させたいと思ったのですが、その認識で正しい(上記(2)は間違い)ということでいいのでしょうか。 もし、画面遷移が必要でない(「フォトライブラリを開く」というボタンの下のUIImageViewに表示できればいい)ということであれば、少し簡単に解決します。コメントいただければと思います。 また、もう一度「やってみたいこと」と「実際の流れ」を確認してみてはいかがでしょうか(私の回答を最初から順を追ってよく確認してみてください。magieeさんがやりたいことと、実際ご自身で書かれたコードがどのように違っているのか、なぜ動きが違うのかを順を追って説明しています)。
magiee

2020/05/08 10:16

仕様が曖昧で申し訳ございません。 現状のswiftの動き。 ①アプリを起動すると、画面遷移前の画面が開き、ライブラリが開くボタンが押せる。 ②ライブラリが開き、画像を選択するとライブラリが閉じる。(選択した画像は遷移先にも表示されない) 目指すswiftの動き。 ①アプリを起動すると、画面遷移前の画面が開き、ライブラリが開くボタンが押せる。 ②ライブラリが開き、画像を選択するとライブラリが閉じる。 ③ライブラリが閉じると、遷移前のimageViewに表示され、また遷移後のimageViewにも表示される。 という物を作りたいです。 それに向けて、まず選択した画像を遷移後のimageViewに表示させたいと思い、 コードを記載したのですが、うまくいきませんでした。(前回の回答のコード) //選択された画像を表示するViewContorllerにセットする. secondViewController.mySelectedImage = myImage as? UIImage このコードで、選択した画像を遷移後のimageViewに選択できると思ったのですが、違うのでしょうか??
TsukubaDepot

2020/05/08 23:02

私に謝る必要はありませんよ。 詳細を明確にすることがきちんと動くアプリを作るためには必要な作業ですから、順番に明確にしたいと思いますのでお付き合いください。 > ③ライブラリが閉じると、遷移前のimageViewに表示され、また遷移後のimageViewにも表示される。 ここですが、遷移前のimageView、遷移後のimageViewの両方に表示するのはいいのですが、画面の遷移はどのようなタイミングで行う予定でしょうか。両方の操作の間にはなんらかの操作が入るかと思いますが、いかがでしょうか。
TsukubaDepot

2020/05/08 23:04

> //選択された画像を表示するViewContorllerにセットする. > secondViewController.mySelectedImage = myImage as? UIImage > このコードで、選択した画像を遷移後のimageViewに選択できると思ったのですが、違うのでしょうか?? 遷移後だけ見ればその通りです。 しかし、遷移前にmyImageに必要となる画像データをセットしておく必要があります。 そのためには、各メソッドの役割と、OSが自動で呼ぶメソッドの順番と、自分で各メソッドの順番をきちんと把握しておく必要もあります。
magiee

2020/05/09 11:00

回答していただきありがとうございます。 私のイメージとしては、 ③ライブラリが閉じると、「選択した画像はこちらです」というサンプル的な意味合いで遷移前のimageViewに表示。そして、遷移後に実際に表示する。という形となります。両方の操作の間には何も操作は入りません。 > secondViewController.mySelectedImage = myImage as? UIImage のコードで、遷移後のimageViewに選択できるのですが、 >myImagePicker.pushViewController(secondViewController, animated: true) のコードを消してしまうと、表示されなくなり、ここをどのようにコードを記載すれば良いのか分からない状況です。
magiee

2020/05/09 11:00

私のイメージを整理して気付いたのですが、伝えられていない部分がありました。 ③ライブラリが閉じると、遷移前のimageViewに表示される。 ④NavigationVarにある、BarButtonItemで、画面遷移を行う。 ⑤遷移後のimageViewに表示される。 という流れが私の求める動きでした。 イメージを伝える大切さを知ることができました。ありがとうございます。
TsukubaDepot

2020/05/09 11:24

これで、流れが整理できたかと思います。 整理すると、 ①アイコンをタップするとviewControllerが開く ②「フォトライブラリを開く」ボタンを押すとフォトライブラリが起動する ③ライブラリが閉じると、遷移前のimageViewに表示される。 ④NavigationBarにある、BarButtonItemで、画面遷移を行う。 ⑤遷移後のimageViewに表示される。 という流れになりますね。 そうすると、 ①アイコンをタップするとviewControllerが開く -> viewDidLoadは基本的な設定だけ行う -> viewDidAppearでpresentを実行すると、起動直後にフォトライブラリが開くので削除する ②「フォトライブラリを開く」ボタンを押すとフォトライブラリが起動する -> 「フォトライブラリを開く」と関連づけられたアクション(メソッド)内でフォトライブラリをpresentする ③ライブラリが閉じると、遷移前のimageViewに表示される。 -> imagePickerController(delegateとなるメソッド)が呼び出されるので、ここでイメージビューに表示する -> imagePickerController内でpushViewControllerを実行すると、ライブラリが閉じた瞬間に次の画面に遷移するので削除する ④NavigationBarにある、BarButtonItemで、画面遷移を行う。 -> BarButtonItemから遷移先の画面にSegueを引っ張っているのであればperformSegueを実行し、prepare メソッド内で値を渡す -> pushViewController を使うのであれば、次の画面をインスタンス化(instantinateViewController)し、次の画面のクラス内にあるプロパティに値を渡した後にpushViewControllerを実行する ⑤遷移後のimageViewに表示される。 -> 遷移後のviewDidLoadで遷移後の画面のImageViewに画像をセットする という流れになると思います。 上の流れを注意深くみていただくと、なぜ突然画面が遷移したり、あるいはイメージピッカーが起動したのか理解していただけるかと思います。 従って、まずは上記の要件を整理し、どこでどのメソッドを実行するか確認し、それからコードに落とし込むといいかと思います。 最初に提示していただいたコードが全く意味を成していないわけではなく、ただメソッドを実行すべき場所が間違っているだけですので、大きくは変える必要はないと思います。 コメントお待ちしています。
magiee

2020/05/09 12:55

整理された順序に沿ってコードを記載すると、④までできました。ありがとうございます。 残りは、⑤なのですが、 「遷移後のviewDidLoadで遷移前の画像を遷移後のImageViewに画像をセットする」 が、どのように記載すれば良いのか分かりません。 ご教授のほどよろしくお願い致します。 //①アイコンをタップするとviewControllerが開く import UIKit class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate { var myImagePicker: UIImagePickerController! override func viewDidLoad() { super.viewDidLoad() self.title = "設定モード" } //②「フォトライブラリを開く」ボタンを押すとフォトライブラリが起動する @IBAction func photoLibraryButton(_ sender: Any) { // インスタンス生成 myImagePicker = UIImagePickerController() // デリゲート設定 myImagePicker.delegate = self present(myImagePicker, animated: true, completion: nil) } //画像が選択された時に呼ばれるメソッド func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { //選択した画像を配置したsampleViewに渡す sampleView.image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage // モーダルビューを閉じる self.dismiss(animated: true, completion: nil) } //画像選択がキャンセルされた時に呼ばれる. func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { // モーダルビューを閉じる self.dismiss(animated: true, completion: nil) } //③ライブラリが閉じると、遷移前のimageViewに表示される。 @IBOutlet weak var sampleView: UIImageView! //④NavigationBarにある、BarButtonItemで、画面遷移を行う。 @IBAction func nextpages(_ sender: Any) { performSegue(withIdentifier: "nextPages", sender: nil) } }
TsukubaDepot

2020/05/09 13:32

難しく考えなくても大丈夫ですよ。 概念になりますが、sampleViewで override func viewDidLoad() { super.viewDidLoad() imageView.image = image } みたいな感じにすればいいと思います。 上記のコードもあと一歩の感じもしますが、まずは動かしてみてください。
magiee

2020/05/09 14:48

申し訳ございません。分かりません。 遷移前のUIImageViewを、遷移後のUIImageviewにも与える、というコードが全く分かりません。 「sampleViewで」っというのは、どういうことでしょうか。 単に、遷移後のコードに override func viewDidLoad() { super.viewDidLoad() imageView.image = image } を記載するのでは無いのはなんとなく分かりますが、、、。
TsukubaDepot

2020/05/09 14:53

たぶん、一気にいろんなことに挑戦しているので、少し混乱しているのだと思います。 少しお待ちいただければ(明日になるかもしれませんが)、21時55分のコードを検証して、動かなければ動くようにコメントして回答に追加したいと思います。 たぶん、コードをみていただければ「そういうことか」と納得いただけると思います。
magiee

2020/05/09 14:59

かしこまりました。 お手数をおかけします。 自分でも、できるよう奮闘してみます。
TsukubaDepot

2020/05/10 00:43

回答本文に追記しました。 詳しくはコメント(特にMARK: の部分)を参考にしていただけますでしょうか。
magiee

2020/05/10 02:00

回答して頂きありがとうございます。 納得することができました。問題なく動きました。 ただ少し気になるところがあります。2点ほど質問をさせてください。 1点目 ②「フォトライブラリを開く」ボタンを押すとフォトライブラリが起動するの所で、5つ工程があります。 // A:インスタンス生成 // B:デリゲート設定 // C:画像の取得先はフォトライブラリ // D:画像取得後の編集を不可に   // E:MARK: ここでイメージピッカーを表示させる この5つの工程をのなかで、CとDを削っても同じように動作しました。 // インスタンス生成 // デリゲート設定 //ここでイメージピッカーを表示させる。 この、Dは編集の有無なのでなくても問題なさそうだなと感じるのですが、Cがなくてもできてしまう理由は何故でしょうか?必要ないコードなのか、たまたまうまく動いているだけなのか、気になります。 2点目 // ③ライブラリが閉じると、遷移前のimageViewに表示される。の所で、 TsukubaDepotさんが記載したコード // 選択された画像を取得 if let myImage = info[.originalImage] as? UIImage { // 遷移前の画面に画像を表示する sampleView.image = myImage 私が記載したコード //選択した画像を配置したsampleViewに渡す sampleView.image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage で、多少コードの記載が違いますが同じような動作をしている為、どちらのコードでも問題ないのでしょうが、TsukubaDepotさんが記載したコードに何かしらのメリットがあるのでしょうか? よろしくお願い致します。
TsukubaDepot

2020/05/10 02:41

https://developer.apple.com/documentation/uikit/uiimagepickercontroller/1619167-sourcetype に記載されていますが、デフォルトの値は .photoLibrary なので、指定しなければ自動的にフォトライブラリになります(削除しても結果が同じなのはこの理由からです)。 info[]の中は Enum 値を指定すると分かっているので、構造体名やEnum名は省略することが可能です。 また、試しに[] の中で . (ドット)だけ打ち込んでみればわかりますが、自動的に設定できる値が補完されるので、ドキュメントを読まなくても見当がつくという利点もあります。
TsukubaDepot

2020/05/10 02:41

// 遷移前の画面に画像を表示する sampleView.image = myImage 上記の行がない場合、遷移する前の画面には画像が表示されないはずです。 試しにコメントアウトしてみて実行してみてはいかがでしょうか。
magiee

2020/05/10 02:59

デフォルトがフォトライブラリだから削除しても問題ないとのことだったんですね。 また、sampleView.image = myImageを消すと、表示されなくなりました。 分かりやすい説明をしていただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問