对于相册的操作网上有很多文章,也有很多讲解,我们今天来实现相册的多选功能。我们利用Photo.framework,这个是iOS8以后的版本。我们先熟悉一个这个框架的基本的几个类。
这里有一篇文章,写的很好具体的功能不论述了,我们直接来看逻辑。
我们先创建一个相册管理器,主要负责获取相册和照片,我们来看代码。
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地址。到此结束。