はじめに
写真アプリを作った時に「フォトライブラリから写真を複数同時に取り込む機能」の実装でハマったことがあったので、記事にしてみようと思います。
写真の取り込みだけならUIImagePickerControllerでかなり簡単に実現できるのですが、1枚ずつしか選択できないという制限があり、これをカスタマイズする方法がどうしても見つけられませんでした。関連する記事をいろいろ見てみたんですけど、きっと現時点では方法がないんじゃないかと。
となると、Photos.Framework…ということになるんですけど、やりたいことに対してドンピシャな情報がなかなか見つけられないんですよね。
ライブラリを使うという選択肢もあるんですけど、自分の場合は「とりあえずコピペして動かしてみる」からの「コードが読み解けてきたら自由にカスタマイズ」というやり方が好きな脳筋なので、同じような人の役に立てばと思っています。
環境
Xcode 11.2.1
Swift 5.1.2
実現したい機能はこんな感じ
作る画面は3つ
- メイン - フォトライブラリの起動ボタンがあり、選択した写真の一覧を表示する画面
- アルバム一覧 - フォトライブラリのアルバム一覧
- 写真一覧 - 選択したアルバム内の写真一覧を表示し、写真を選択する画面
【注】レイアウトはStoryBoardを使わずにコードのみで、主にAutoLayoutを使っています。
<<<
2020/2/29追記:コードが長くて重過ぎたので、コードはGitHubに公開して、記事はポイントのみの記述に変更しました。
kozitex/PhotosMultiSelect
>>>
1.メイン
ここは特筆すべきところは特にありません。
フォトライブラリで写真を選んで戻ってくると、選んだ写真のサムネイルが表示される、という画面です。
以下の2ファイルで構成しています。
コレクションビューとカスタムセルで写真のサムネイルを表示しています。
MainViewCell.swift
MainViewController.swift
2.アルバム一覧
メイン画面で「+」を押すと、まずこの画面が開きます。
どのアルバムから写真を探す?っていう画面です。
以下の2ファイルで構成しています。
テーブルビューとカスタムセルです。
LibraryAlbumViewCell.swift
LibraryAlbumViewController.swift
ポイントとしては、PHAssetCollectionTypeとPHAssetCollectionSubtypeを使って、端末内のアルバム一覧を取得・表示しているところでしょうか。
~~
20 let collectionTypes = [(type: PHAssetCollectionType.smartAlbum, name: ""), (type: PHAssetCollectionType.album, name: "マイアルバム")]
21
22 let collectionSubTypes = [[PHAssetCollectionSubtype.smartAlbumUserLibrary, PHAssetCollectionSubtype.smartAlbumRecentlyAdded, PHAssetCollectionSubtype.smartAlbumFavorites, PHAssetCollectionSubtype.smartAlbumTimelapses, PHAssetCollectionSubtype.smartAlbumVideos, PHAssetCollectionSubtype.smartAlbumSelfPortraits, PHAssetCollectionSubtype.smartAlbumScreenshots], [PHAssetCollectionSubtype.albumRegular]]
~~
~~
81 for i in 0...1 {
82
83 let collectionType = collectionTypes[i].type
84
85 var albumList: [(name: String, count: Int, images: [UIImage], collection: PHAssetCollection)] = []
86
87 for collectionSubType in collectionSubTypes[i] {
88
89 let collectionLists = getCollectionLists(collectionType: collectionType, collectionSubType: collectionSubType)
90
91 for collectionList in collectionLists {
92
93 albumList.append(collectionList)
94 }
95 }
96
97 data.append(albumList)
98 }
~~
以下のサイトがとっても参考になりました。感謝m(_ _)mです。
PHAssetCollectionType早見表
Photos Frameworkでアルバムのサムネイルを取得する
PhotoKitの使い方メモ
ただ、UIImagePickerControllerの画面デザインに寄せようとしたばかりに、ちょっとコードが冗長になってしまいました。この画面は省略できると思いますので、お好みで。
3.写真一覧
ここが今回のキモ、写真を複数選択する画面です。
LibraryPhotoViewCell.swift
LibraryPhotoViewController.swift
LibraryPhotoViewHeader.swift
ポイントはいろいろあるんですが、1つはチェックマークの有無をdidsetで状態管理しているところでしょうか。
~~
177 // MARK: isMarked
178 var isMarked: Bool = false {
179
180 didSet {
181
182 if isMarked {
183
184 contentView.addSubview(checkmarkView)
185 checkmarkView.addSubview(checkmarkLabel)
186 contentView.bringSubviewToFront(checkButton)
187
188 checkmarkView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0).isActive = true
189 checkmarkView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 0).isActive = true
190 checkmarkView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 0).isActive = true
191 checkmarkView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0).isActive = true
192
193 checkmarkLabel.centerXAnchor.constraint(equalTo: checkButton.centerXAnchor, constant: 0).isActive = true
194 checkmarkLabel.centerYAnchor.constraint(equalTo: checkButton.centerYAnchor, constant: 0).isActive = true
195 checkmarkLabel.widthAnchor.constraint(equalToConstant: 26).isActive = true
196 checkmarkLabel.heightAnchor.constraint(equalToConstant: 26).isActive = true
197
198 } else {
199
200 checkmarkView.removeFromSuperview()
201 }
202 }
203 }
~~
こちらのサイトが大変参考になりました。とにかくコードがキレイで分かりやすい!見習いたいです。
[Swift] UICollectionViewCell にチェックマークをつける
あとは、撮影日でグルーピングしてセクションヘッダーで一括選択できるようにしていたり、ツールバーで選択中のアイテムの個数を表示していたり、などなど。
オリジナル要素もいくつか入れていますが、余力があったら切り出して細かい解説を入れたい…。いつか。
補足
上記の他にこのプログラムを動かすには以下の設定が必要になります。
-
Info.plist
アプリでフォトライブラリを使用するにはInfo.plistに以下の許可設定を追加する必要があります。この辺りはけっこう情報が多いので、ここでは省略させていただきます。
Privacy - Photo Library Usage Description
Privacy - Photo Library Additions Usage Description -
チェックマークのアイコン
今回はFontAwesomeのアイコンを使わせてもらいました。
使い方は以下の記事を参考にさせていただいています。
iOSでFont Awesomeを使う
その他参考にしたURL
UITableViewのUX改善(今すぐ出来る!)
[Swift] 一度だけ実行したい処理をクロージャでスマートに書く
最後に
至らない点や無駄な記述など、お気付きの点はご指摘いただけるとありがたいです!