-
提要
对于相册的操作网上有很多文章,也有很多讲解,我们今天来实现相册的多选功能。我们利用Photo.framework,这个是iOS8以后的版本。我们先熟悉一个这个框架的基本的几个类。
- PHAsset:一个资源的相片
- PHAssetCollection:继承PHCollection的子类,单个资源的集合,如相册、时刻等
- PHCollectionList:继承PHCollection的子类,集合的集合,如相册文件夹
- PHPhotoLibrary:相册的管理操作,负责注册通知、检查和请求获取权限
- PHImageManager:按照要求获取制定的图片
- PHCachingImageManager:PHImageManager的子类
- PHAssetChangeRequest:编辑相册,增删改查
这里有一篇文章,写的很好具体的功能不论述了,我们直接来看逻辑。
-
创建
我们先创建一个相册管理器,主要负责获取相册和照片,我们来看代码。
class JHSAssetManger: NSObject {
weak var changeObserver: JHSAssetMangerDelegate?
private var allPhoto: PHFetchResult<PHAsset>! // 所有照片
private var smartALbums: PHFetchResult<PHAssetCollection>! // 智能相册集
private var userCollecions: PHFetchResult<PHCollection>! // 用户自定相册集和
var model = JHAassetModel();
override init() {
super.init();
model.resetAssetList();
let allOptions = PHFetchOptions();
allOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)];
allPhoto = PHAsset.fetchAssets(with: allOptions);
let item = JHSAssetItemModel(asset: allPhoto);
if item.count > 0 {
model.addItemModel(model: item);
}
smartALbums = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumRegular, options: nil);
smartALbums.enumerateObjects { (collection, idx, stop) in
let item = JHSAssetItemModel(collection: collection, type: .smart);
if item.count > 0 {
self.model.addItemModel(model: item);
}
}
userCollecions = PHCollectionList.fetchTopLevelUserCollections(with: nil);
userCollecions.enumerateObjects { (collection, idx, stop) in
let item = JHSAssetItemModel(collection: collection, type: .collection);
if item.count > 0 {
self.model.addItemModel(model: item);
}
}
PHPhotoLibrary.shared().register(self);
}
deinit {
PHPhotoLibrary.shared().unregisterChangeObserver(self);
}
}
我们需要接收这个管理器所获取到的所有有相册集和照片。我们需要封装成统一的数据模型Model。下面是数据模型。
class JHSAssetItemModel: NSObject {
var type = JHSAssetModelType.image;
var results: PHFetchResult<PHAsset>!
var collection: PHAssetCollection!
var chachesImage = [String:UIImage]();
var title = "";
var count: Int {
return results?.count ?? 0;
}
private override init() {
super.init();
}
convenience init(collection: PHCollection,type: JHSAssetModelType = JHSAssetModelType.image) {
self.init();
if let asset = collection as? PHAssetCollection {
title = asset.localizedTitle ?? "";
results = PHAsset.fetchAssets(in: asset, options: nil);
self.collection = asset;
}
self.type = type;
}
convenience init(asset: PHFetchResult<PHAsset>) {
self.init();
title = "全部照片";
results = asset;
}
func fetchImage(index: Int,size: CGSize,finished:@escaping ((_ image: UIImage?) -> Void)) -> Void {
let key = NSStringFromRange(NSRange(location: size.width.intValue, length: size.height.intValue)) + "\(index)" + (collection?.localIdentifier ?? "");
if let img = chachesImage[key] {
finished(img);
return;
}
if results == nil || count <= index {
finished(nil);
return;
}
let asset = results.object(at: index);
let dispath = DispatchQueue(label: "fetch_image");
dispath.async {
let options = PHImageRequestOptions();
options.isSynchronous = true;
PHCachingImageManager.default().requestImage(for: asset, targetSize: CGSize(width: size.width, height: size.height), contentMode: PHImageContentMode.default, options: options) { (image, dict) in
self.chachesImage[key] = image;
DispatchQueue.main.async {
finished(image);
}
};
}
}
}
这个数据模型只是代表一个资源,我们需要一个类来管理不同集合的资源。我们还需要定义一个模型的管理器。
enum JHSAssetModelType: Int {
case image
case smart
case collection
}
class JHAassetModel{
private var assetList: [JHSAssetModelType:[JHSAssetItemModel]]!;
init() {
assetList = [JHSAssetModelType:[JHSAssetItemModel]]();
}
func addItemModel(model: JHSAssetItemModel) -> Void {
var list = assetList[model.type] ?? [JHSAssetItemModel]();
list.append(model);
assetList[model.type] = list;
}
func resetType(type: JHSAssetModelType) -> Void {
assetList.removeValue(forKey: type);
}
subscript(type: JHSAssetModelType) -> [JHSAssetItemModel]? {
return assetList[type];
}
func resetAssetList() -> Void {
assetList.removeAll();
}
}
上边的JHSAssetModelType是表示资源的集合类型。我们需要知道我们的是对那个集合资源进行操作。
这就是一些的基本的相册的逻辑操作,下面我们看界面。
我们需要一个类表来显示当前的相册集合。
import UIKit
import Photos
class JHSPhotoTableController: JHSBaseViewController {
var photoManger = JHSAssetManger();
var maxCount = 10; // 最多选择的张数 默认是10个
var finished:((_ list: [UIImage]) -> Void)!
override func viewDidLoad() {
super.viewDidLoad()
photoManger.changeObserver = self;
createTable(delegate: self);
baseTable.register(UITableViewCell.self, forCellReuseIdentifier: "cell");
}
// MAEK: - table view delegate implement
override func numberOfSections(in tableView: UITableView) -> Int {
return 3;
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let type = JHSAssetModelType(rawValue: section)!
return photoManger.model[type]?.count ?? 0;
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath);
let type = JHSAssetModelType(rawValue: indexPath.section)!
let list = photoManger.model[type];
let itemModel = list?[indexPath.row];
cell.textLabel?.text = itemModel?.title;
return cell;
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let ctrl = JHSPhotoController();
let type = JHSAssetModelType(rawValue: indexPath.section)!
let list = photoManger.model[type];
ctrl.itemModel = list?[indexPath.row];
ctrl.manger = photoManger;
ctrl.finishedDone = finished;
navigationController?.pushViewController(ctrl, animated: true);
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let titles = ["所有", "智能", "用户"];
return titles[section];
}
}
extension JHSPhotoTableController: JHSAssetMangerDelegate {
func assetManger(manger: JHSAssetManger, operation: JHSOperation) {
if operation.operation == .smartAlbum {
baseTable.reloadSections(section: 1);
}
if operation.operation == .userCollection {
baseTable.reloadSections(section: 2);
}
}
}
我们需要创建一个另外的显示集合里的所有照片的控制器。
class JHSPhotoController: JHSBaseViewController {
// var models: JHSPhotoModel?
var itemModel: JHSAssetItemModel!
var manger: JHSAssetManger!
var finishedDone:((_ list: [UIImage]) -> Void)!
var selectedRows = [Int]() {
didSet{
navigationItem.rightBarButtonItem?.title = "\(selectedRows.count)个"
}
}
override func viewDidLoad() {
super.viewDidLoad()
createPhoneLevel();
let countItem = UIBarButtonItem(title: "0个", style: .plain, target: self, action: #selector(buttonItemAction(_:)));
self.navigationItem.rightBarButtonItem = countItem;
// guard let collection = itemModel?.collection else {
// return;
// }
// if collection.canPerform(.addContent) {
// let addImg = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(buttonItemAction(_:)));
// navigationItem.rightBarButtonItem = addImg;
// }else if collection.canPerform(.delete) {
// let addImg = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(buttonItemAction(_:)));
// navigationItem.rightBarButtonItem = addImg;
// }
}
@objc override func buttonItemAction(_ item: UIBarButtonItem) {
var list = [UIImage]();
var count = 0;
for idx in selectedRows {
itemModel?.fetchImage(index: idx, size: ScreenData.bounds.size, finished: { (image) in
list.append(image!);
count += 1;
if count == self.selectedRows.count {
self.finishedDone?(list);
}
})
}
self.navigationController?.dismiss(animated: true, completion: {
})
}
}
extension JHSPhotoController: UICollectionViewDelegate,UICollectionViewDataSource {
func createPhoneLevel() -> Void {
let layout = UICollectionViewFlowLayout();
layout.minimumLineSpacing = 4;
layout.minimumInteritemSpacing = 4;
layout.sectionInset = UIEdge(size: 4);
let perWidth = (width() - 20)/4;
layout.itemSize = CGSize(width: perWidth, height: perWidth);
createCollection(frame: navigateRect, layout: layout, delegate: self);
baseCollectionView.register(JHSPhotoImageCell.self, forCellWithReuseIdentifier: "JHSPhotoImageCell");
baseCollectionView.alwaysBounceVertical = true;
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return itemModel?.count ?? 0;
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "JHSPhotoImageCell", for: indexPath) as! JHSPhotoImageCell;
cell.isSelected = selectedRows.contains(indexPath.row);
cell.selectedButn.addTarget(self, action: #selector(touchUpButtonAction(_:)));
itemModel.fetchImage(index: indexPath.row, size: CGSize(width: width()/2, height: width()/2)) { (image) in
cell.imageView.image = image;
}
return cell;
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let ctrl = JHSImageController();
ctrl.index = indexPath.row;
ctrl.modelItems = itemModel;
navigationController?.pushViewController(ctrl, animated: true);
}
override func touchUpButtonAction(_ btn: UIButton) {
guard let cell = btn.superview as? JHSPhotoImageCell else {
return;
}
let indexPath = baseCollectionView.indexPath(for: cell)!;
if let idx = selectedRows.firstIndex(of: indexPath.row) {
selectedRows.remove(at: idx);
cell.isSelected = false;
}else{
cell.isSelected = true;
selectedRows.append(indexPath.row);
}
}
}
这样就基本上就可以使用了。展示效果。如下图:
demo总还是有的。demo地址。到此结束。