Edited at

UIImagePickerController表示中にsourceTypeを切り替える


TL;DR

表示中のUIImagePickerControllersourceType変更はうまく動かない

→ カメラ起動、フォトライブラリ起動でボタンを分けて先にsourceType決めさせる

→ またはインスタンス再生成する


やりたいこと

カメラを起動して撮影した画像を取得したい。

また、オプションとしてフォトライブラリ内からも画像を選択できるようにしたい。


やったこと


実装方針

UIImagePickerControllerでカメラを起動

フォトライブラリボタンがタップされたらUIImagePickerControllersourceTypecameraからphotoLibraryに変更する


ソース

本来はUIImagePickerControllercameraOverlayViewを使用して

カメラ表示中にフォトライブラリボタンを設ける予定だが、

とりあえずテストのためpickerのキャンセルボタンでsourceType切り替えを実装


FirstViewController.swift

import UIKit

import Photos

class FirstViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

var picker: UIImagePickerController!

override func viewDidLoad() {
super.viewDidLoad()
// 許可リクエスト
AVCaptureDevice.requestAccess(for: AVMediaType.video) { (Bool) in
return
}
}

/// Picker起動ボタン
///
/// - Parameter sender:
@IBAction func btn1_TouchUpInside(_ sender: Any) {
pickerInit(type: UIImagePickerController.SourceType.camera)
}

/// Picker初期化
///
/// - Parameter type: sourceType
func pickerInit(type: UIImagePickerController.SourceType){
self.picker = UIImagePickerController()
self.picker.sourceType = type
self.picker.delegate = self

self.picker.navigationBar.tintColor = UIColor.white
self.picker.navigationBar.barTintColor = UIColor.gray

present(self.picker, animated: false, completion: nil)
}

// MARK: - UIImagePickerControllerのデリゲートメソッド

/// 画像選択時
///
/// - Parameters:
/// - picker:
/// - info:
private func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// モーダルビューを閉じる
self.picker.dismiss(animated: true, completion: nil)
}

/// キャンセル時
///
/// - Parameter picker:
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
// 表示中のpickerのsourceTypeを切り替えるだけ
if picker.sourceType == UIImagePickerController.SourceType.photoLibrary {
self.picker.sourceType = UIImagePickerController.SourceType.camera
}
else {
self.picker.sourceType = UIImagePickerController.SourceType.photoLibrary
}
}
}



結果


スクショ

1.起動時

起動時.PNG

2.Picker起動(カメラ)

カメラ.png

3.sourceType切り替え(フォトライブラリ)

フォトライブラリ.PNG

4.sourceType切り替え(カメラ)

カメラ.png

5.sourceType切り替え(フォトライブラリ)

フォトライブラリ?.PNG

!!!?!?!!???!!?!??!?!???wwwwwwwww

カメラは普通なのにフォトライブラリ2回目表示すると何も出ない!なんやこれ!!


デバッグ

落ち着け…

俺には(最近覚えた)レイアウトデバッグがある…!

1.正常時

スクリーンショット 2018-10-12 12.51.44.png

2.異常時

スクリーンショット 2018-10-12 12.52.28.png

PUPhotoPickerHostViewControllerの霊圧が消えた…!?

ていうか誰だよコイツ!ググっても全然わかんねぇ!!

あっ…フレームワークさんちのお子さん…?

それじゃあ仕方ないわねぇウフフ

結局見てもよくわかりませんでした。


じゃあどうするか

一回作ったUIImagePickerControllerでコロコロsourceType変えてるのがまずいと予想。

写真撮影とフォトライブラリからの選択はボタン分けてるアプリばっかりだし。


実装方針

UIImagePickerControllerでカメラを起動

フォトライブラリボタンがタップされたら表示中のUIImagePickerControllersourceType変更ではなく、sourceTypeを変更したUIImagePickerControllerインスタンスを新規で生成する。


ソース

本来はカメラ表示中にフォトライブラリボタンを設ける予定だが以下略


SecondViewController.swift

import UIKit

import Photos

class SecondViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate{

var picker: UIImagePickerController!

override func viewDidLoad() {
super.viewDidLoad()
// 許可リクエスト
AVCaptureDevice.requestAccess(for: AVMediaType.video) { (Bool) in
return
}
}

/// Picker起動ボタン
///
/// - Parameter sender:
@IBAction func btn1_TouchUpInside(_ sender: Any) {
pickerInit(type: UIImagePickerController.SourceType.camera)
}

/// Picker初期化
///
/// - Parameter type: sourceType
func pickerInit(type: UIImagePickerController.SourceType){
self.picker = UIImagePickerController()
self.picker.sourceType = type
self.picker.delegate = self

self.picker.navigationBar.tintColor = UIColor.white
self.picker.navigationBar.barTintColor = UIColor.gray

present(self.picker, animated: false, completion: nil)
}

// MARK: - UIImagePickerControllerのデリゲートメソッド

/// 画像選択時
///
/// - Parameters:
/// - picker:
/// - info:
private func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

// モーダルビューを閉じる
self.picker.dismiss(animated: true, completion: nil)
}

/// キャンセル時
///
/// - Parameter picker:
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
// 一旦表示中のモーダルを閉じる
self.picker.dismiss(animated: false, completion: nil)

// sourceTypeを切り替えて再度インスタンス生成から行う
if picker.sourceType == UIImagePickerController.SourceType.photoLibrary {
pickerInit(type: UIImagePickerController.SourceType.camera)
}
else {
pickerInit(type: UIImagePickerController.SourceType.photoLibrary)
}
}
}



結果

何度切り替えを行なっても正常にカメラ、フォトライブラリが表示されるようになりました。


まとめ

ぶっちゃけ要因はよくわかりませんでした。

表示中のUIImagePickerControllersourceType変更はガイドラインに沿ってないのかなぁ…?

一旦このやり方で解決はしたけど、もっと楽な方法とかありそう。