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

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

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

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

Swift

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

Q&A

解決済

1回答

10295閲覧

[swift]カメラアプリの横向き対応ができない

programan

総合スコア25

Xcode

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

Swift

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

0グッド

0クリップ

投稿2018/06/15 15:04

デバイスを横向きにしたときにキャプチャー画面を横向きに対応させたい

swiftでカメラアプリの開発ををしています。
デバイスを横向きにしたときに以下の画像のようにキャプチャー画面を横向きに対応させることができませんでした。

デバイスが縦向きの場合
イメージ説明
デバイスが横向きの場合
イメージ説明

ViewController.swift

import UIKit import AVFoundation import Photos extension UIViewController:AVCapturePhotoCaptureDelegate { //映像をキャプチャする public func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { //データを取り出す guard let photoData = photo.fileDataRepresentation() else { return } //Dataから写真イメージを作る if let stillImage = UIImage(data: photoData) { //移動先のビューコントローラーを参照する let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "preview")as! previewViewController //トランジションの映像効果を指定する // nextVC?.modalTransitionStyle = .flipHorizontal nextVC.image = stillImage //シーンを移動する present(nextVC, animated: true, completion: nil) } } } class ViewController: UIViewController { @IBOutlet weak var previewView: UIView! @IBOutlet weak var shutterButton: UIButton! // インスタンスの作成 var session = AVCaptureSession() var photoOutputObj = AVCapturePhotoOutput() // 通知センターを作る let notification = NotificationCenter.default // プライバシーと入出力のステータス var authStatus:AuthorizedStatus = .authorized var inOutStatus:InputOutputStatus = .ready // 認証のステータス enum AuthorizedStatus { case authorized case notAuthorized case failed } // 入出力のステータス enum InputOutputStatus { case ready case notReady case failed } // ビューが表示された直後に実行 override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // セッション実行中ならば中断する guard !session.isRunning else { return } // カメラのプライバシー認証確認 cameraAuth() // 入出力の設定 setupInputOutput() // カメラの準備ができているかどうか if (authStatus == .authorized)&&(inOutStatus == .ready){ // プレビューレイヤの設定 setPreviewLayer() // セッション開始 session.startRunning() shutterButton.isEnabled = true } else { // アラートを出す showAlert(appName: "カメラ") } // デバイスが回転したときに通知するイベントハンドラを設定する notification.addObserver(self, selector: #selector(self.changedDeviceOrientation(_:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } // シャッターボタンで実行する @IBAction func takePhoto(_ sender: Any) { if (authStatus == .authorized)&&(inOutStatus == .ready){ let captureSetting = AVCapturePhotoSettings() captureSetting.flashMode = .auto captureSetting.isAutoStillImageStabilizationEnabled = true captureSetting.isHighResolutionPhotoEnabled = false // キャプチャのイメージ処理はデリゲートに任せる photoOutputObj.capturePhoto(with: captureSetting, delegate: self) } else { // カメラの利用を許可しなかったにも関わらずボタンをタップした(初回起動時のみ) showAlert(appName: "カメラ") } } // カメラのプライバシー認証確認 func cameraAuth(){ let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.video) switch status { case .notDetermined: // 初回起動時 AVCaptureDevice.requestAccess(for: AVMediaType.video, completionHandler: { [unowned self] authorized in print("初回", authorized.description) if authorized { self.authStatus = .authorized } else { self.authStatus = .notAuthorized }}) case .restricted, .denied: authStatus = .notAuthorized case .authorized: authStatus = .authorized } } // 入出力の設定 func setupInputOutput(){ //解像度の指定 session.sessionPreset = AVCaptureSession.Preset.photo // 入力の設定 do { //デバイスの取得 let device = AVCaptureDevice.default( AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: AVMediaType.video, // ビデオ入力 position: AVCaptureDevice.Position.back) // バックカメラ // 入力元 let input = try AVCaptureDeviceInput(device: device!) if session.canAddInput(input){ session.addInput(input) } else { print("セッションに入力を追加できなかった") return } } catch let error as NSError { print("カメラがない (error)") return } // 出力の設定 if session.canAddOutput(photoOutputObj) { session.addOutput(photoOutputObj) } else { print("セッションに出力を追加できなかった") return } } // プレビューレイヤの設定 func setPreviewLayer(){ // プレビューレイヤを作る let previewLayer = AVCaptureVideoPreviewLayer(session: session) previewLayer.frame = view.bounds previewLayer.masksToBounds = true previewLayer.videoGravity = AVLayerVideoGravity.resizeAspect // previewViewに追加する previewView.layer.addSublayer(previewLayer) } // デバイスの向きが変わったときに呼び出すメソッド @objc func changedDeviceOrientation(_ notification :Notification) { // photoOutputObj.connectionの回転向きをデバイスと合わせる if let photoOutputConnection = self.photoOutputObj.connection(with: AVMediaType.video) { switch UIDevice.current.orientation { case .portrait: photoOutputConnection.videoOrientation = .portrait case .portraitUpsideDown: photoOutputConnection.videoOrientation = .portraitUpsideDown case .landscapeLeft: photoOutputConnection.videoOrientation = .landscapeRight case .landscapeRight: photoOutputConnection.videoOrientation = .landscapeLeft default: break } } } // プライバシー認証のアラートを表示する func showAlert(appName:String){ let aTitle = appName + "のプライバシー認証" let aMessage = "設定>プライバシー>" + appName + "で利用を許可してください。" let alert = UIAlertController(title: aTitle, message: aMessage, preferredStyle: .alert) // OKボタン(何も実行しない) alert.addAction( UIAlertAction(title: "OK",style: .default,handler: nil) ) // 設定を開くボタン alert.addAction( UIAlertAction( title: "設定を開く",style: .default, handler: { action in UIApplication.shared.open(URL(string: UIApplicationOpenSettingsURLString)!, options: [:], completionHandler: nil) }) ) // アラートを表示する self.present(alert, animated: false, completion:nil) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }

試したこと

Main.storyboardでViewをオートレイアウトのconstraintsで4辺からの距離を0で固定をしましたがうまくいきませんでした。

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

xcode9.4

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

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

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

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

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

guest

回答1

0

ベストアンサー

以下のページを参考にして書き換えてみました、横向き対応もできましたので確認してみてください。
Swift - iOSでビデオカメラを使用時、端末の向きに対応

swift

1 2import UIKit 3import AVFoundation 4import Photos 5 6extension UIViewController:AVCapturePhotoCaptureDelegate { 7 //映像をキャプチャする 8 public func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { 9 //データを取り出す 10 guard let photoData = photo.fileDataRepresentation() else { 11 return 12 } 13 //Dataから写真イメージを作る 14 if let stillImage = UIImage(data: photoData) { 15 //移動先のビューコントローラーを参照する 16 let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "preview")as! previewViewController 17 //トランジションの映像効果を指定する 18 // nextVC?.modalTransitionStyle = .flipHorizontal 19 nextVC.image = stillImage 20 //シーンを移動する 21 present(nextVC, animated: true, completion: nil) 22 } 23 } 24} 25 26class ViewController: UIViewController { 27 28 @IBOutlet weak var previewView: UIView! 29 @IBOutlet weak var shutterButton: UIButton! 30 31 var previewLayer: AVCaptureVideoPreviewLayer! 32 // インスタンスの作成 33 var session = AVCaptureSession() 34 var photoOutputObj = AVCapturePhotoOutput() 35 // 通知センターを作る 36 let notification = NotificationCenter.default 37 // プライバシーと入出力のステータス 38 var authStatus:AuthorizedStatus = .authorized 39 var inOutStatus:InputOutputStatus = .ready 40 // 認証のステータス 41 enum AuthorizedStatus { 42 case authorized 43 case notAuthorized 44 case failed 45 } 46 // 入出力のステータス 47 enum InputOutputStatus { 48 case ready 49 case notReady 50 case failed 51 } 52 53 // ビューが表示された直後に実行 54 override func viewDidAppear(_ animated: Bool) { 55 super.viewDidAppear(animated) 56 // セッション実行中ならば中断する 57 guard !session.isRunning else { 58 return 59 } 60 // カメラのプライバシー認証確認 61 cameraAuth() 62 // 入出力の設定 63 setupInputOutput() 64 // カメラの準備ができているかどうか 65 if (authStatus == .authorized)&&(inOutStatus == .ready){ 66 // プレビューレイヤの設定 67 setPreviewLayer() 68 // セッション開始 69 session.startRunning() 70 shutterButton.isEnabled = true 71 } else { 72 // アラートを出す 73 showAlert(appName: "カメラ") 74 } 75 } 76 77 // シャッターボタンで実行する 78 @IBAction func takePhoto(_ sender: Any) { 79 if (authStatus == .authorized)&&(inOutStatus == .ready){ 80 let captureSetting = AVCapturePhotoSettings() 81 captureSetting.flashMode = .auto 82 captureSetting.isAutoStillImageStabilizationEnabled = true 83 captureSetting.isHighResolutionPhotoEnabled = false 84 // キャプチャのイメージ処理はデリゲートに任せる 85 photoOutputObj.capturePhoto(with: captureSetting, delegate: self) 86 } else { 87 // カメラの利用を許可しなかったにも関わらずボタンをタップした(初回起動時のみ) 88 showAlert(appName: "カメラ") 89 } 90 } 91 92 // カメラのプライバシー認証確認 93 func cameraAuth(){ 94 let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.video) 95 switch status { 96 case .notDetermined: 97 // 初回起動時 98 AVCaptureDevice.requestAccess(for: AVMediaType.video, 99 completionHandler: { [unowned self] authorized in 100 print("初回", authorized.description) 101 if authorized { 102 self.authStatus = .authorized 103 } else { 104 self.authStatus = .notAuthorized 105 }}) 106 case .restricted, .denied: 107 authStatus = .notAuthorized 108 case .authorized: 109 authStatus = .authorized 110 } 111 } 112 113 // 入出力の設定 114 func setupInputOutput(){ 115 //解像度の指定 116 session.sessionPreset = AVCaptureSession.Preset.photo 117 // 入力の設定 118 do { 119 //デバイスの取得 120 let device = AVCaptureDevice.default( 121 AVCaptureDevice.DeviceType.builtInWideAngleCamera, 122 for: AVMediaType.video, // ビデオ入力 123 position: AVCaptureDevice.Position.back) // バックカメラ 124 125 // 入力元 126 let input = try AVCaptureDeviceInput(device: device!) 127 if session.canAddInput(input){ 128 session.addInput(input) 129 } else { 130 print("セッションに入力を追加できなかった") 131 return 132 } 133 } catch let error as NSError { 134 print("カメラがない (error)") 135 return 136 } 137 138 // 出力の設定 139 if session.canAddOutput(photoOutputObj) { 140 session.addOutput(photoOutputObj) 141 } else { 142 print("セッションに出力を追加できなかった") 143 return 144 } 145 } 146 147 // UIInterfaceOrientation -> AVCaptureVideoOrientationにConvert 148 func convertUIOrientation2VideoOrientation(f: () -> UIInterfaceOrientation) -> AVCaptureVideoOrientation? { 149 let v = f() 150 switch v { 151 case UIInterfaceOrientation.unknown: return nil 152 default: 153 return ([ 154 .portrait: .portrait, 155 .portraitUpsideDown: .portraitUpsideDown, 156 .landscapeLeft: .landscapeLeft, 157 .landscapeRight: .landscapeRight 158 ])[v] 159 } 160 } 161 162 func appOrientation() -> UIInterfaceOrientation { 163 return UIApplication.shared.statusBarOrientation 164 } 165 166 // プレビューレイヤの設定 167 func setPreviewLayer(){ 168 // プレビューレイヤを作る 169 previewLayer = AVCaptureVideoPreviewLayer(session: session) 170 previewLayer.frame = view.bounds 171 previewLayer.masksToBounds = true 172 previewLayer.videoGravity = AVLayerVideoGravity.resizeAspect 173 if let orientation = self.convertUIOrientation2VideoOrientation(f: { return self.appOrientation() } ) { 174 previewLayer.connection?.videoOrientation = orientation 175 } 176 // previewViewに追加する 177 previewView.layer.addSublayer(previewLayer) 178 } 179 180 override func viewDidLayoutSubviews() { 181 super.viewDidLayoutSubviews() 182 183 if let previewLayer = previewLayer { 184 previewLayer.frame = view.bounds 185 } 186 } 187 188 // 画面の回転にも対応したい時は viewWillTransitionToSize で同じく向きを教える。 189 override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 190 super.viewWillTransition(to: size, with: coordinator) 191 192 coordinator.animate( 193 alongsideTransition: nil, 194 completion: {(UIViewControllerTransitionCoordinatorContext) in 195 //画面の回転後に向きを教える。 196 if let orientation = self.convertUIOrientation2VideoOrientation(f: {return self.appOrientation()}) { 197 self.previewLayer.connection?.videoOrientation = orientation 198 } 199 } 200 ) 201 } 202 203 // プライバシー認証のアラートを表示する 204 func showAlert(appName:String){ 205 let aTitle = appName + "のプライバシー認証" 206 let aMessage = "設定>プライバシー>" + appName + "で利用を許可してください。" 207 let alert = UIAlertController(title: aTitle, message: aMessage, preferredStyle: .alert) 208 // OKボタン(何も実行しない) 209 alert.addAction( 210 UIAlertAction(title: "OK",style: .default,handler: nil) 211 ) 212 // 設定を開くボタン 213 alert.addAction( 214 UIAlertAction( 215 title: "設定を開く",style: .default, 216 handler: { action in 217 UIApplication.shared.open(URL(string: UIApplicationOpenSettingsURLString)!, options: [:], completionHandler: nil) 218 }) 219 ) 220 // アラートを表示する 221 self.present(alert, animated: false, completion:nil) 222 } 223}

投稿2018/06/16 16:07

_Kentarou

総合スコア8490

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

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

programan

2018/06/19 11:38

自分が思った通りにうまく実装できました。 ありがとうございます 仕組みがまだ理解できていないので改めて読んで勉強してみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問