//tips
//カメラアプリ作成
Swiftcodeからカメラを操作するアプリを作成する。カメラを起動しての写真撮影と撮影画像の表示を行わせる。
まず土台となるコードを下記に記載する。
import SwiftUI
struct ContentView: View {
@State var image:Image?
@State var isPicking = false
var body: some View {
ZStack {
VStack {
VStack {
Spacer()
image?
.resizable()
.scaledToFit()
Spacer()
}
HStack {
Spacer()
Button(action: {
self.isPicking = true
}) {
Image(systemName:"camera")
Text("カメラ")
}.padding()
}
}
if isPicking{
Rectangle()
.edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
.transition(.move(edge: .bottom))
.animation(.easeInOut)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
今回利用したspacerは空白部分を組み込む部品で、デバイスの上下に空白部分を組み込むことでimageの表示部分を上下から若干離した場所に表示させている。
また、bodyにUI部品を追加・削除・切り替えが行われた時、transitionを使うことでアニメーションを発生させることができる。
Button(action: {self.isPicking = true})
ボタンをクリックした時にf isPicking以下を行わせるためにtransitionを用いている。
.transition(.move(edge: .bottom))
で下からせり上がるアニメーションを設定している。
transitionの種類としては、
move():上下左右のいずれかから元の位置に移動
opacity:透明から不透明へ
scale:無から元のサイズへ拡大
slide:左から元の位置に移動
offset():指定した位置から元の位置へ移動
このRectangle()のように切り替え時に最上面に表示したいものをモーダルビューと言い、その中でもいくつかの種類がある。
例えば、sheet()メソッドのように画面上部にだけ隙間を残すもの、actionSheet()メソッドという下部に複数の選択肢を示す画面を出すもの、alert()メソッドのように中央に注意喚起の文言を記載したものなど、Zstack構造体を用いる手法以外も知っておくと便利である。
//写真ライブラリの追加
Content view.swiftを選択した状態で左下のプラスボタンからnew fileをクリックし、swiftUIviewを選ぶ。
ImagePickerという名前でCameraAppフォルダ内に生成する。
そうするとヒエラルキーに新たなファイルができるので、スクリプトを記述。
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.sourceType = .photoLibrary
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {
}
}
struct ImagePicker_Previews: PreviewProvider {
static var previews: some View {
ImagePicker()
}
}
これではImagePickerのみで完結してしまうので、contentviewと連動させる。これはrectangle()をImagePicker()に書き換えればいいだけ。カメラボタンを押すと先のImagePicker()の内容が表示される。
Viewプロトコルの代わりに、UIviewControllerRepresentableプロトコルを批准しており、その中の約束事として、
makeUIViewController()メソッド:UIKitフレームワークにある部品のインスタンスを作るメソッド
updateUIViewController()メソッド:UIKitフレームワークにある部品を更新するメソッド
の組み込みが必要となる。
//swiftでのカメラ操作
ユーザーのカメラをswiftで操作する。左下のプラスからswift fileでnew fileを作成。
下記を記載。
import SwiftUI
class Coordinator:NSObject,UINavigationControllerDelegate,UIImagePickerControllerDelegate{
var parent:ImagePicker
init(_ parent:ImagePicker){
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let uiImage = info[.originalImage] as! UIImage
UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
}
}
これをImagePicker.swiftに組み込み下記のように書き換えた。
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.sourceType = .camera
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {
}
}
struct ImagePicker_Previews: PreviewProvider {
static var previews: some View {
ImagePicker()
}
}
同時にカメラ機能の使用をユーザーに許可してもらうため、左のInfo.plistからsupported interface orientationsのプラスを押し、privacy-camera usage description,カメラ利用許可 privacy-photo library additions usage description写真ライブラリ利用許可を追加する。
これによりアラートが表示されるようになる。
Info.plistはアプリの設定ファイルで、制作中のアプリに関する様々な項目が設定されている。プライバシーに係る項目は、これらの設定をきちんと行っておかないのでアプリがクラッシュするので要注意。
ここからはスクリプトの理解を行う。
まず下記の部分だが、
class Coordinator:NSObject,UINavigationControllerDelegate,UIImagePickerControllerDelegate{
Coordinator:の後ろは構造体のようにプロトコルを宣言する部分ではなく、クラスの親子関係を表している。
子クラス:親クラス・・・
Coordinator:NSObject・・・
となり、子クラスには、親クラスのプロパティやメソッドが引き継がれる。継承と言われ、構造体にはなく、クラスのみが持つ特性になっている。
継承を行う理由はコードの重複を最小限に抑えることにあり、構造体のプロトコルと役割は同じである。
Coordinator:NSObject・・・はCoordinatorクラスの親クラスにNSObjectを持つことを指している。
ただ、実際に必要なのは、NSObject以下に書かれているUINavigationControllerDelegate,UIImagePickerControllerDelegateの部分で、これらを継承するために、その親であるNSObjectを継承する必要があったのでコードを組み込んでいる。
ただ、子クラスは1つの親しか指定できないので、NSObject以下は何かというと、プロトコルを表している。プロトコルは親とは異なり、複数批准できる。
class Coordinator:NSObject,UINavigationControllerDelegate,UIImagePickerControllerDelegate{
UINavigationControllerDelegate:画像取得画面を操作するメソッドが宣言されている
UIImagePickerControllerDelegate:複数の画面に表示するのに必要なメソッドが宣言されている。これは通常画面とアラート画面の切り替えなどのこと。
ちなみに、プロトコルを批准せず下記の imagePickerControllerを記載しなかった場合、ユーザーが撮影した画像を、iosで、保存したり、編集したりできない仕様になる。
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let uiImage = info[.originalImage] as! UIImage
UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
}
クラスとプロトコルのイメージは下記が分かりやすかった。