参考:http://www.hangge.com/blog/cache/detail_1512.html

ios14 使用PHPicker获取相册(需要 import PhotosUI)

  • 支持多选
  • 支持搜索
  • 独立的进程
  • 内置隐私
    • 不需要直接访问用户相册
    • 不会弹出访问相册提示
    • 仅提供用户选择的照片和视频(App 无法获取其他照片)

PHPicker 是由系统提供的选择器,可以访问用户相册里的照片和视频。它内置了搜索功能,支持网格中的流体缩放,以及经常会被用到的照片多选功能。

PHPicker 运行在应用程序的进程之外,尽管它看起来像是在应用程序内部运行。它实际上是在一个独立的进程中运行,而不是在它上面呈现的宿主应用。但是该应用不能直接访问选择器,甚至不能截屏选择器内容。只有用户实际选择的内容才会传递回主机应用程序。

PHPickerViewController 依然是通过 delegate 属性来向宿主 App 返回用户选择的结果。

PHPickerConfiguration 。 PHPickerConfiguration 有两个可选属性 selectionLimit 和 filter 。 selectionLimit 默认值为 1,表示单选。若要多选,则设置为 0; filter 指定相册显示类型,可单独设置,也可用数组形式显示多种类型。

代理方法中用户选择的结果会以 PHPickerResult 数组的形式传入,每一个 PHPickerResult 都对应一个照片、视频或者 LivePhoto 的数据。PHPickerResult 只有 itemProvider 和 assetIdentifier 两个属性,剩下的是继承的 Equatable 和 Hashable 协议的实现。

assetIdentifier这是选中对象对应的 PHAsset 的 id,可以用这个 id 通过 PHAset 的相关 api 来进行其他操作。不过苹果在 WWDC 的介绍视频中明确强调了如果要访问 PHAsset 的额外信息,依然需要获取到相册权限后才可以执行。

通过 itemProvider 的 api,我们可以获取到最终的结果,不过这里有点小麻烦:针对照片、视频和 LivePhoto 三种媒体类型,分别要使用不同的 api 来获取;

1.获取照片,通过 NSItemProvider 的 loadObject 方法,并且指定 Class 类型为 UIImage,就可以在回调中得到 UIImage 类型的照片了。

//获取图片

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {

picker.dismiss(animated: true, completion: nil)

//下面只是获取了一张图片

//获取PHPickerResult的itemProvider

if let itemProvider = results.first?.itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self) {

// 通过 NSItemProvider 的 loadObject 方法,并且指定 Class 类型为 UIImage,就可以在回调中得到 UIImage 类型的照片了; [weak self]

itemProvider.loadObject(ofClass: UIImage.self) { image, error in

print("一张图片\(String(describing: image))")

DispatchQueue.main.async {

//在主线更新UI

}

}

}

}

2.获取 LivePhoto 与获取照片类似,只是需要将 UIImage 替换为 PHLivePhoto。之后你可以通过 PHLivePhotoView 来显示。或者通过 PHAssetResourceManager 获取 LivePhoto 的原始数据。

//获取LivePhoto

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {

picker.dismiss(animated: true, completion: nil)

//下面只是获取了一张图片

//获取PHPickerResult的itemProvider

if let itemProvider = results.first?.itemProvider, itemProvider.canLoadObject(ofClass: PHLivePhoto.self) {

// 通过 NSItemProvider 的 loadObject 方法,并且指定 Class 类型为 UIImage,就可以在回调中得到 UIImage 类型的照片了; [weak self]

itemProvider.loadObject(ofClass: PHLivePhoto.self) { [weak self] phlivephoto, error in

print("phlivephoto\(String(describing: phlivephoto))")

let livephoto = PHLivePhotoView.init(frame: CGRect.init(x: 0, y: 0, width: 300, height: 300))

livephoto.livePhoto=(phlivephoto as! PHLivePhoto)

self?.view.addSubview(livephoto)

}

}

}

3.获取视频,使用 loadFileRepresentation 方法来加载大文件(包括视频)。loadFileRepresentation 的使用方式与 UIImage 类似,但需要额外传入一个参数 forTypeIdentifier 来指定文件类型,指定为 public.movie 可以覆盖相册中的 .mov 和 .mp4 类型。与照片不同的是,这个 api 返回的是一个 URL 类型的临时文件路径,苹果在这个 API 的说明中指出:系统会把请求的文件数据复制到这个路径对应的地址,并且在回调执行完毕后删除临时文件。

//获取视频

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {

picker.dismiss(animated: true, completion: nil)

//下面只是获取了一张图片

//获取PHPickerResult的itemProvider

if let itemProvider = results.first?.itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self) {

//这个 api 返回的是一个 URL 类型的临时文件路径,苹果在这个 API 的说明中指出:系统会把请求的文件数据复制到这个路径对应的地址,并且在回调执行完毕后删除临时文件。

itemProvider.loadFileRepresentation(forTypeIdentifier: "public.movie") { url, error in

}

}

}

配置PHPicker:

    @available(iOS 14, *)func setPHPicekr(){var config = PHPickerConfiguration()// 可选择的资源数量,0表示不设限制,默认为1config.selectionLimit = 0// 可选择的资源类型// 只显示图片(注:images 包含 livePhotos)config.filter = .images// 显示 Live Photos 和视频(注:livePhotos 不包含 images)
//        config.filter = .any(of: [.livePhotos, .videos])// 如果要获取视频,最好设置该属性,避免系统对视频进行转码,默认是automaticconfig.preferredAssetRepresentationMode = .currentlet picker = PHPickerViewController(configuration: config)picker.delegate = selfpresent(picker, animated: true, completion: nil)}

综合:

 var selectType = "image" //"video" "livephoto"@available(iOS 14, *)func setPHPicekr(){var config = PHPickerConfiguration()// 可选择的资源数量,0表示不设限制,默认为1config.selectionLimit = 0// 可选择的资源类型// 只显示图片(注:images 包含 livePhotos)config.filter = .images// 显示 Live Photos 和视频(注:livePhotos 不包含 images)
//        config.filter = .any(of: [.livePhotos, .videos])// 如果要获取视频,最好设置该属性,避免系统对视频进行转码,默认是automatic,会自动转码config.preferredAssetRepresentationMode = .currentlet picker = PHPickerViewController(configuration: config)picker.delegate = selfpresent(picker, animated: true, completion: nil)}//获取图片@available(iOS 14, *)func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {picker.dismiss(animated: true, completion: nil)if selectType=="image"{//下面只是获取了一张图片//获取PHPickerResult的itemProviderif let itemProvider = results.first?.itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self) {// 通过 NSItemProvider 的 loadObject 方法,并且指定 Class 类型为 UIImage,就可以在回调中得到 UIImage 类型的照片了; [weak self]itemProvider.loadObject(ofClass: UIImage.self) { image, error inprint("一张图片\(String(describing: image))")DispatchQueue.main.async {//在主线更新UI}}}}else if selectType=="live"{//视频//获取PHPickerResult的itemProviderif let itemProvider = results.first?.itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self) {//这个 api 返回的是一个 URL 类型的临时文件路径,苹果在这个 API 的说明中指出:系统会把请求的文件数据复制到这个路径对应的地址,并且在回调执行完毕后删除临时文件。
itemProvider.loadFileRepresentation(forTypeIdentifier: "public.movie") { url, error in}}}else if selectType=="livephoto"{//livephoto//获取PHPickerResult的itemProviderif let itemProvider = results.first?.itemProvider, itemProvider.canLoadObject(ofClass: PHLivePhoto.self) {// 通过 NSItemProvider 的 loadObject 方法,并且指定 Class 类型为 UIImage,就可以在回调中得到 UIImage 类型的照片了; [weak self]itemProvider.loadObject(ofClass: PHLivePhoto.self) { [weak self] phlivephoto, error inprint("phlivephoto\(String(describing: phlivephoto))")let livephoto = PHLivePhotoView.init(frame: CGRect.init(x: 0, y: 0, width: 300, height: 300))livephoto.livePhoto=(phlivephoto as! PHLivePhoto)
//                    self?.view.addSubview(livephoto)}}}}

ios8-13使用Photos获取相册(需要import Photos)

1。***********获取系统相册的照片和录像*********

 let assetArr: [PHAsset] =  getAllAlbumAndPHAsset()//获取照片资源//吧强求到图片资源转换成UIIMgae,在回掉方法中获取图片data数据,然后做相应的操作DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+1) {self.getImageFromPHAsset(asset: assetArr[0], size: CGSize.init(width: 100, height: 100))}********************////1.获取所有PHAsset资源的集合,包含视频和照片func getAllPHAssetFromSysytem()->([PHAsset]){var arr:[PHAsset] = []let options = PHFetchOptions.init()let assetsFetchResults:PHFetchResult = PHAsset.fetchAssets(with: options)// 遍历,得到每一个图片资源asset,然后放到集合中assetsFetchResults.enumerateObjects { (asset, index, stop) inarr.append(asset)}print("\(arr.count)")return arr}//2.先获取所有相册,然后从相机胶卷中获取PHAsset集合,(相机胶卷是相册中的一个,包含了所有视频和相册)func getAllAlbumAndPHAsset()->([PHAsset]){var arr:[PHAsset] = []let options = PHFetchOptions.init()// 所有智能相册集合(系统自动创建的相册)let smartAlbums:PHFetchResult = PHAssetCollection.fetchAssetCollections(with: PHAssetCollectionType.smartAlbum, subtype: PHAssetCollectionSubtype.albumRegular, options: options)//遍历得到每一个相册for i in 0..<smartAlbums.count {// 是否按创建时间排序let options = PHFetchOptions.init()options.sortDescriptors = [NSSortDescriptor(key: "creationDate",ascending: false)]//时间排序options.predicate = NSPredicate.init(format: "mediaType == %ld", PHAssetMediaType.image.rawValue)//˙只选照片let collection:PHCollection  = smartAlbums[i];//得到一个相册,一个集合就是一个相册/**相册标题英文:Portrait、Long Exposure、Panoramas、Hidden、Recently Deleted、Live Photos、Videos、Animated、Recently Added、Slo-mo、Time-lapse、Bursts、Camera Roll、Screenshots、Favorites、Selfies*/print("相册标题---%@",collection.localizedTitle as Any);//遍历获取相册if collection is PHAssetCollection {if collection.localizedTitle == "相机胶卷" || collection.localizedTitle == "Camera Roll"{//相册的名字是相机交卷,这里面包含了所有的资源,包括照片、视频、gif。 注意相册名字中英文let assetCollection = collection as! PHAssetCollection//collection中的资源都统一使用PHFetchResult 对象封装起来。//得到PHFetchResult封装的图片资源集合let fetchResult:PHFetchResult = PHAsset.fetchAssets(in: assetCollection, options: nil)var assetArr:[PHAsset] = []if fetchResult.count>0{//某个相册里面的所有PHAsset对象(PHAsset对象对应的是图片,需要通过方法请求到图片)assetArr  = getAllPHAssetFromOneAlbum(assetCollection: assetCollection)arr.append(contentsOf: assetArr)}}}}return arr}//获取一个相册里的所有图片的PHAsset对象func getAllPHAssetFromOneAlbum(assetCollection:PHAssetCollection)->([PHAsset]){// 存放所有图片对象var arr:[PHAsset] = []// 是否按创建时间排序let options = PHFetchOptions.init()options.sortDescriptors = [NSSortDescriptor(key: "creationDate",ascending: false)]//时间排序options.predicate = NSPredicate.init(format: "mediaType == %ld", PHAssetMediaType.image.rawValue)//˙只选照片// 获取所有图片资源对象let results:PHFetchResult = PHAsset.fetchAssets(in: assetCollection, options: options)// 遍历,得到每一个图片资源asset,然后放到集合中results.enumerateObjects { (asset, index, stop) inprint("\(asset)")arr.append(asset)}return arr}根据PHAsset获取原图片信息func getImageFromPHAsset(asset:PHAsset,size:CGSize){var requestID:PHImageRequestID = -2let scale:CGFloat = CGFloat(UIScreen.main.scale)let width:CGFloat = CGFloat(min(WIDTH, 500))if (requestID >= 1 && (size.width) / width == scale) {PHCachingImageManager.default().cancelImageRequest(requestID)}let option:PHImageRequestOptions=PHImageRequestOptions.init()option.deliveryMode = PHImageRequestOptionsDeliveryMode.opportunisticoption.resizeMode = PHImageRequestOptionsResizeMode.fast;requestID = PHCachingImageManager.default().requestImageData(for: asset, options: option, resultHandler: { (Dat, str, orientation, [AnyHashable : Any]?) in//Dat是图片数据self.image = UIImage.init(data: Dat!)self.collec?.reloadData()})//请求视频的
//        requestID = PHCachingImageManager.default().requestAVAsset(forVideo: PHAsset, options: PHVideoRequestOptions?, resultHandler: { (<#AVAsset?#>, AVAudioMix?, [AnyHashable : Any]?) in
//
//        })}

2.*************获取所有相册显示在collectionview,分页加载***************

/**用来显示所有的相册照片使用: let looAlbum = LYBMutipleSelectAlbumView.init(frame: CGRect.init(x: 0, y: 0, width: Int(WIDTH), height: Int(HEIGHT)-Int(bottomSafeHeight)))view.addSubview(looAlbum)}*/
import UIKit
import Photos
class LYBMutipleSelectAlbumView: UIView,UICollectionViewDelegate,UICollectionViewDataSource {var collec:UICollectionView?var image:UIImage!=UIImage.init(named: "appstart")var imageArr:[UIImage]=[]//获取到的图片数组var assetArr: [PHAsset]=[]//获取所有照片资源var index:Int = 0//记录显示图片的最大索引let step:Int = 12//每次加载多少张图片override init(frame: CGRect) {super.init(frame: frame)assetArr =  getAllAlbumAndPHAsset()//获取照片资源createCollectionView()//吧强求到图片资源转换成UIIMgae,在回掉方法中获取图片data数据,然后做相应的操作pullUprefresh()//先刷新一下}required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}func createCollectionView(){let flowLayout = UICollectionViewFlowLayout.init()flowLayout.itemSize=CGSize.init(width: WIDTH/4, height: WIDTH/4)flowLayout.minimumLineSpacing=0flowLayout.minimumInteritemSpacing=0collec = UICollectionView.init(frame: CGRect.init(x: 0, y: 0, width: Int(WIDTH), height: Int(HEIGHT)-Int(bottomSafeHeight)-Int(TopSpaceHigh)), collectionViewLayout: flowLayout)collec?.backgroundColor=UIColor.whitecollec?.delegate=selfcollec?.dataSource=selfcollec?.register(LYBMutipleSelectAlbumCollectionviewcell.classForCoder(), forCellWithReuseIdentifier: "LYBMutipleSelectAlbumCollectionviewcell")addSubview(collec!)initNormalAutoFooterRefresh()//上拉加载}//上拉加载func initNormalAutoFooterRefresh(){let footer =  MJRefreshAutoNormalFooter()//上刷新相关设置footer.setRefreshingTarget(self, refreshingAction: #selector(pullUprefresh))//self.bottom_footer.stateLabel.isHidden = true // 隐藏文字//是否自动加载(默认为true,即表格滑到底部就自动加载,这个我建议关掉,要不然效果会不好)footer.isAutomaticallyRefresh = falsefooter.isAutomaticallyChangeAlpha = true //自动更改透明度//修改文字footer.setTitle("上拉加载", for: .idle)//普通闲置的状态footer.setTitle("正在加载中", for: .refreshing)//正在刷新的状态footer.setTitle("加载完成", for: .noMoreData)//数据加载完毕的状态collec?.mj_footer=footer}//上拉刷新@objc func pullUprefresh(){if(assetArr.count<=step){//所有资源小于10个,加载实际的个数for i in 0..<assetArr.count{self.getImageFromPHAsset(asset:assetArr[i], size: CGSize.init(width: 100, height: 100))}collec?.mj_footer.endRefreshingWithNoMoreData()//没有更多数据}else {index+=stepif assetArr.count>index{for i in index-step..<index{self.getImageFromPHAsset(asset:assetArr[i], size: CGSize.init(width: 100, height: 100))}}else{//最后几个元素if assetArr.count>index-step && assetArr.count<index{for i in index..<assetArr.count{self.getImageFromPHAsset(asset:assetArr[i], size: CGSize.init(width: 100, height: 100))}}}}print("上拉刷新")//因为获取图片是异步加载的,所以延迟刷线DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+1) {self.collec?.mj_footer.endRefreshing()self.collec?.reloadData()}}func numberOfSections(in collectionView: UICollectionView) -> Int {return 1}func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {return imageArr.count}func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {let cell:LYBMutipleSelectAlbumCollectionviewcell = collectionView.dequeueReusableCell(withReuseIdentifier: "LYBMutipleSelectAlbumCollectionviewcell", for: indexPath) as! LYBMutipleSelectAlbumCollectionviewcellcell.image = imageArr[indexPath.item]cell.backgroundColor=UIColor.redreturn cell}//1.获取所有PHAsset资源的集合,包含视频和照片func getAllPHAssetFromSysytem()->([PHAsset]){var arr:[PHAsset] = []let options = PHFetchOptions.init()let assetsFetchResults:PHFetchResult = PHAsset.fetchAssets(with: options)// 遍历,得到每一个图片资源asset,然后放到集合中assetsFetchResults.enumerateObjects { (asset, index, stop) inarr.append(asset)}print("\(arr.count)")return arr}//2.先获取所有相册,然后从相机胶卷中获取PHAsset集合,(相机胶卷是相册中的一个,包含了所有视频和相册)func getAllAlbumAndPHAsset()->([PHAsset]){var arr:[PHAsset] = []let options = PHFetchOptions.init()// 所有智能相册集合(系统自动创建的相册)let smartAlbums:PHFetchResult = PHAssetCollection.fetchAssetCollections(with: PHAssetCollectionType.smartAlbum, subtype: PHAssetCollectionSubtype.albumRegular, options: options)//遍历得到每一个相册for i in 0..<smartAlbums.count {// 是否按创建时间排序let options = PHFetchOptions.init()options.sortDescriptors = [NSSortDescriptor(key: "creationDate",ascending: false)]//时间排序options.predicate = NSPredicate.init(format: "mediaType == %ld", PHAssetMediaType.image.rawValue)//˙只选照片let collection:PHCollection  = smartAlbums[i];//得到一个相册,一个集合就是一个相册/**相册标题英文:Portrait、Long Exposure、Panoramas、Hidden、Recently Deleted、Live Photos、Videos、Animated、Recently Added、Slo-mo、Time-lapse、Bursts、Camera Roll、Screenshots、Favorites、Selfies*/print("相册标题---%@",collection.localizedTitle as Any);//遍历获取相册if collection is PHAssetCollection {if collection.localizedTitle == "相机胶卷" || collection.localizedTitle == "Camera Roll"{//相册的名字是相机交卷,这里面包含了所有的资源,包括照片、视频、gif。 注意相册名字中英文let assetCollection = collection as! PHAssetCollection//collection中的资源都统一使用PHFetchResult 对象封装起来。//得到PHFetchResult封装的图片资源集合let fetchResult:PHFetchResult = PHAsset.fetchAssets(in: assetCollection, options: nil)var assetArr:[PHAsset] = []if fetchResult.count>0{//某个相册里面的所有PHAsset对象(PHAsset对象对应的是图片,需要通过方法请求到图片)assetArr  = getAllPHAssetFromOneAlbum(assetCollection: assetCollection)arr.append(contentsOf: assetArr)}}}}return arr}//获取一个相册里的所有图片的PHAsset对象func getAllPHAssetFromOneAlbum(assetCollection:PHAssetCollection)->([PHAsset]){// 存放所有图片对象var arr:[PHAsset] = []// 是否按创建时间排序let options = PHFetchOptions.init()options.sortDescriptors = [NSSortDescriptor(key: "creationDate",ascending: false)]//时间排序options.predicate = NSPredicate.init(format: "mediaType == %ld", PHAssetMediaType.image.rawValue)//˙只选照片// 获取所有图片资源对象let results:PHFetchResult = PHAsset.fetchAssets(in: assetCollection, options: options)// 遍历,得到每一个图片资源asset,然后放到集合中results.enumerateObjects { (asset, index, stop) inprint("\(asset)")arr.append(asset)}return arr}根据PHAsset获取原图片信息func getImageFromPHAsset(asset:PHAsset,size:CGSize){var requestID:PHImageRequestID = -2let scale:CGFloat = CGFloat(UIScreen.main.scale)let width:CGFloat = CGFloat(min(WIDTH, 500))if (requestID >= 1 && (size.width) / width == scale) {PHCachingImageManager.default().cancelImageRequest(requestID)}let option:PHImageRequestOptions=PHImageRequestOptions.init()option.deliveryMode = PHImageRequestOptionsDeliveryMode.opportunisticoption.resizeMode = PHImageRequestOptionsResizeMode.fast;requestID = PHCachingImageManager.default().requestImageData(for: asset, options: option, resultHandler: { (Dat, str, orientation, [AnyHashable : Any]?) in//Dat是图片数据,吧UIIMage加入到数组中let image:UIImage=UIImage.init(data: Dat!)!self.imageArr.append(image)})//请求视频的//        requestID = PHCachingImageManager.default().requestAVAsset(forVideo: PHAsset, options: PHVideoRequestOptions?, resultHandler: { (<#AVAsset?#>, AVAudioMix?, [AnyHashable : Any]?) in////        })}}*************/**相册多选的cell*/
import UIKitclass LYBMutipleSelectAlbumCollectionviewcell: UICollectionViewCell {var imageV:UIImageView!var image:UIImage=UIImage.init(named: "appstart")!{willSet(image) {}didSet {imageV.image=image}}override init(frame: CGRect) {super.init(frame: frame)createCell()}required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}func createCell(){imageV = UIImageView.init(frame:CGRect.init(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))imageV.image=UIImage.init(named: "appstart")addSubview(imageV)}}

3.**************相册多选封装***************

/**//设置为不选中状态collectionView.deselectItem(at: indexPath, animated: false)//这个是用来获取所有的indexpathcollectionView.indexPathsForSelectedItems用来显示所有的相册照片使用: let looAlbum = LYBMutipleSelectAlbumView.init(frame: CGRect.init(x: 0, y: 0, width: Int(WIDTH), height: Int(HEIGHT)-Int(bottomSafeHeight)))looAlbum.selectBlock={(selectimageArr)inprint("\(selectimageArr)")}view.addSubview(looAlbum)*/
import UIKit
import Photos
class LYBMutipleSelectAlbumView: UIView,UICollectionViewDelegate,UICollectionViewDataSource {var collec:UICollectionView?var image:UIImage!=UIImage.init(named: "appstart")var imageArr:[UIImage]=[]//从系统相册获取到的图片数组var assetArr: [PHAsset]=[]//从系统相册获取所有照片资源var index:Int = 0//记录显示图片的最大索引let step:Int = 12//每次加载多少张图片var isSelectCell:Bool=false//是否选中cell,默认不选中,不显示对号var indexArr:[Int]=[]//存放选中cell序号的数组var selectImageArr:[UIImage]=[]//选中的cell对应的图片//确认按钮,选中照片var selectBlock:([UIImage])->()={([UIImage])->()in}override init(frame: CGRect) {super.init(frame: frame)assetArr =  getAllAlbumAndPHAsset()//获取照片资源createCollectionView()//吧强求到图片资源转换成UIIMgae,在回掉方法中获取图片data数据,然后做相应的操作pullUprefresh()//先刷新一下}required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}lazy var sureAndCancelView:UIView={let v:UIView=UIView.init(frame: CGRect.init(x: 0, y: 0, width: WIDTH, height: 50))let cancelBtn:UIButton=UIButton.init(frame: CGRect.init(x: 20, y: 0, width: 100, height: 50))cancelBtn.setTitle("取消", for: UIControl.State.normal)cancelBtn.addTarget(self, action: #selector(cancelClick), for: UIControl.Event.touchUpInside)cancelBtn.setTitleColor(UIColor.black, for: UIControl.State.normal)v.addSubview(cancelBtn)let sureBtn:UIButton=UIButton.init(frame: CGRect.init(x:WIDTH-120, y: 0, width: 100, height: 50))sureBtn.setTitle("确定", for: UIControl.State.normal)sureBtn.addTarget(self, action: #selector(sureClick), for: UIControl.Event.touchUpInside)sureBtn.setTitleColor(UIColor.black, for: UIControl.State.normal)v.addSubview(sureBtn)return v}()//确定按钮@objc func sureClick(sender:UIButton){print("确定")//吧选中的图片放到一个集合给到外面for index in indexArr{selectImageArr.append(imageArr[index])}selectBlock(selectImageArr)self.removeFromSuperview()}//取消按钮@objc func cancelClick(sender:UIButton){print("取消")self.removeFromSuperview()}func createCollectionView(){addSubview(sureAndCancelView)let flowLayout = UICollectionViewFlowLayout.init()flowLayout.itemSize=CGSize.init(width: WIDTH/4, height: WIDTH/4)flowLayout.minimumLineSpacing=0flowLayout.minimumInteritemSpacing=0collec = UICollectionView.init(frame: CGRect.init(x: 0, y: 50, width: Int(WIDTH), height: Int(HEIGHT)-Int(bottomSafeHeight)-Int(TopSpaceHigh)), collectionViewLayout: flowLayout)collec?.backgroundColor=UIColor.whitecollec?.delegate=selfcollec?.dataSource=self
//        collec?.register(LYBMutipleSelectAlbumCollectionviewcell.classForCoder(), forCellWithReuseIdentifier: "LYBMutipleSelectAlbumCollectionviewcell")addSubview(collec!)collec?.allowsMultipleSelection=true//允许多选initNormalAutoFooterRefresh()//上拉加载}//上拉加载func initNormalAutoFooterRefresh(){let footer =  MJRefreshAutoNormalFooter()//上刷新相关设置footer.setRefreshingTarget(self, refreshingAction: #selector(pullUprefresh))//self.bottom_footer.stateLabel.isHidden = true // 隐藏文字//是否自动加载(默认为true,即表格滑到底部就自动加载,这个我建议关掉,要不然效果会不好)footer.isAutomaticallyRefresh = falsefooter.isAutomaticallyChangeAlpha = true //自动更改透明度//修改文字footer.setTitle("上拉加载", for: .idle)//普通闲置的状态footer.setTitle("正在加载中", for: .refreshing)//正在刷新的状态footer.setTitle("加载完成", for: .noMoreData)//数据加载完毕的状态collec?.mj_footer=footer}//上拉刷新@objc func pullUprefresh(){if(assetArr.count<=step){//所有资源小于10个,加载实际的个数for i in 0..<assetArr.count{self.getImageFromPHAsset(asset:assetArr[i], size: CGSize.init(width: 100, height: 100))}collec?.mj_footer.endRefreshingWithNoMoreData()//没有更多数据}else {index+=stepif assetArr.count>index{for i in index-step..<index{self.getImageFromPHAsset(asset:assetArr[i], size: CGSize.init(width: 100, height: 100))}}else{//最后几个元素if assetArr.count>index-step && assetArr.count<index{for i in index..<assetArr.count{self.getImageFromPHAsset(asset:assetArr[i], size: CGSize.init(width: 100, height: 100))}}}}print("上拉刷新")//因为获取图片是异步加载的,所以延迟刷线DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+1) {self.collec?.mj_footer.endRefreshing()self.collec?.reloadData()}}func numberOfSections(in collectionView: UICollectionView) -> Int {return 1}func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {return imageArr.count}func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {let CellIdentifier:String = String.init(format: "cell%d%d", indexPath.section,indexPath.item)//以indexPath来唯一确定cellcollec?.register(LYBMutipleSelectAlbumCollectionviewcell.classForCoder(), forCellWithReuseIdentifier: CellIdentifier)let  cell:LYBMutipleSelectAlbumCollectionviewcell  = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifier, for: indexPath) as! LYBMutipleSelectAlbumCollectionviewcellcell.image = imageArr[indexPath.item]cell.backgroundColor=UIColor.redreturn cell}func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {collectionView.deselectItem(at: indexPath, animated: true)//取消选中,和显示按钮两回事let cell:LYBMutipleSelectAlbumCollectionviewcell=collectionView.cellForItem(at: indexPath) as! LYBMutipleSelectAlbumCollectionviewcellif indexArr.contains(indexPath.item){//过滤掉已经选中的cell,这里通过filter过滤掉的到一个新的数组,再把新的数组赋值给原来的数组,swift中没有现成的删除指定元素的方法let filterArr  = indexArr.filter {$0 != indexPath.item//数组中留下的元素都是不等于indexPath.item}indexArr=filterArrcell.isSelect=false}else {indexArr.append(indexPath.item)//吧cell的画序号加入到数组cell.isSelect=true}//数组中的序号做一个数组排序,升序indexArr.sort {$0<$1}print("\(indexPath.item)-----\(indexArr)-----")}func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {print("取消选择")}//1.获取所有PHAsset资源的集合,包含视频和照片func getAllPHAssetFromSysytem()->([PHAsset]){var arr:[PHAsset] = []let options = PHFetchOptions.init()let assetsFetchResults:PHFetchResult = PHAsset.fetchAssets(with: options)// 遍历,得到每一个图片资源asset,然后放到集合中assetsFetchResults.enumerateObjects { (asset, index, stop) inarr.append(asset)}print("\(arr.count)")return arr}//2.先获取所有相册,然后从相机胶卷中获取PHAsset集合,(相机胶卷是相册中的一个,包含了所有视频和相册)func getAllAlbumAndPHAsset()->([PHAsset]){var arr:[PHAsset] = []let options = PHFetchOptions.init()// 所有智能相册集合(系统自动创建的相册)let smartAlbums:PHFetchResult = PHAssetCollection.fetchAssetCollections(with: PHAssetCollectionType.smartAlbum, subtype: PHAssetCollectionSubtype.albumRegular, options: options)//遍历得到每一个相册for i in 0..<smartAlbums.count {// 是否按创建时间排序let options = PHFetchOptions.init()options.sortDescriptors = [NSSortDescriptor(key: "creationDate",ascending: false)]//时间排序options.predicate = NSPredicate.init(format: "mediaType == %ld", PHAssetMediaType.image.rawValue)//˙只选照片let collection:PHCollection  = smartAlbums[i];//得到一个相册,一个集合就是一个相册/**相册标题英文:Portrait、Long Exposure、Panoramas、Hidden、Recently Deleted、Live Photos、Videos、Animated、Recently Added、Slo-mo、Time-lapse、Bursts、Camera Roll、Screenshots、Favorites、Selfies*/print("相册标题---%@",collection.localizedTitle as Any);//遍历获取相册if collection is PHAssetCollection {if collection.localizedTitle == "相机胶卷" || collection.localizedTitle == "Camera Roll"{//相册的名字是相机交卷,这里面包含了所有的资源,包括照片、视频、gif。 注意相册名字中英文let assetCollection = collection as! PHAssetCollection//collection中的资源都统一使用PHFetchResult 对象封装起来。//得到PHFetchResult封装的图片资源集合let fetchResult:PHFetchResult = PHAsset.fetchAssets(in: assetCollection, options: nil)var assetArr:[PHAsset] = []if fetchResult.count>0{//某个相册里面的所有PHAsset对象(PHAsset对象对应的是图片,需要通过方法请求到图片)assetArr  = getAllPHAssetFromOneAlbum(assetCollection: assetCollection)arr.append(contentsOf: assetArr)}}}}return arr}//获取一个相册里的所有图片的PHAsset对象func getAllPHAssetFromOneAlbum(assetCollection:PHAssetCollection)->([PHAsset]){// 存放所有图片对象var arr:[PHAsset] = []// 是否按创建时间排序let options = PHFetchOptions.init()options.sortDescriptors = [NSSortDescriptor(key: "creationDate",ascending: false)]//时间排序options.predicate = NSPredicate.init(format: "mediaType == %ld", PHAssetMediaType.image.rawValue)//˙只选照片// 获取所有图片资源对象let results:PHFetchResult = PHAsset.fetchAssets(in: assetCollection, options: options)// 遍历,得到每一个图片资源asset,然后放到集合中results.enumerateObjects { (asset, index, stop) inprint("\(asset)")arr.append(asset)}return arr}根据PHAsset获取原图片信息func getImageFromPHAsset(asset:PHAsset,size:CGSize){var requestID:PHImageRequestID = -2let scale:CGFloat = CGFloat(UIScreen.main.scale)let width:CGFloat = CGFloat(min(WIDTH, 500))if (requestID >= 1 && (size.width) / width == scale) {PHCachingImageManager.default().cancelImageRequest(requestID)}let option:PHImageRequestOptions=PHImageRequestOptions.init()option.deliveryMode = PHImageRequestOptionsDeliveryMode.opportunisticoption.resizeMode = PHImageRequestOptionsResizeMode.fast;requestID = PHCachingImageManager.default().requestImageData(for: asset, options: option, resultHandler: { (Dat, str, orientation, [AnyHashable : Any]?) in//Dat是图片数据,吧UIIMage加入到数组中let image:UIImage=UIImage.init(data: Dat!)!print("\(image.size)---压缩前")//压缩图片let newSize:CGSize = CGSize.init(width: 100, height: 100)UIGraphicsBeginImageContext(newSize)image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))let newImage = UIGraphicsGetImageFromCurrentImageContext()UIGraphicsEndImageContext()print("\(String(describing: newImage))---压缩后")self.imageArr.append(newImage!)})//请求视频的//        requestID = PHCachingImageManager.default().requestAVAsset(forVideo: PHAsset, options: PHVideoRequestOptions?, resultHandler: { (<#AVAsset?#>, AVAudioMix?, [AnyHashable : Any]?) in////        })}}**********/**相册多选的cell*/
import UIKitclass LYBMutipleSelectAlbumCollectionviewcell: UICollectionViewCell {var imageV:UIImageView!var image:UIImage=UIImage.init(named: "appstart")!{willSet(image) {}didSet {imageV.image=image}}//是否选中var isSelect:Bool=false{didSet{print("\(isSelect)")if isSelect{selectbtn.setImage(UIImage.init(named: "comm_btn_checkmark"), for: UIControl.State.normal)}else {selectbtn.setImage(UIImage.init(), for: UIControl.State.normal)}}}override init(frame: CGRect) {super.init(frame: frame)createCell()}required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}func createCell(){imageV = UIImageView.init(frame:CGRect.init(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))imageV.image=UIImage.init(named: "appstart")addSubview(imageV)addSubview(selectbtn)}lazy var selectbtn:UIButton={let btn:UIButton=UIButton.init(frame: CGRect.init(x: 0, y: self.frame.size.width-50, width: 30, height: 30))return btn}()
}

iOS/swift之获取系统所有相册和照片录像、封装相册多选相关推荐

  1. iOS 基于PhotoKit 获取系统所有相册 以及所有照片 包括iCloud的处理 细节详解及实战代码

    前言 最近在做一个相册的项目,一开始觉得项目没什么难度,可是真正上手做了之后,发现难度不小,苹果新推出Photokit之后,获取相册中图片对象是快的,可是在获取到具体图片个人实战比较慢,同时还有icl ...

  2. IOS swift开发——获取设备定位信息

    作为GIS开发人员,学习任何Android或者swift开发语言,可能第一时间想到的就是获取设备的定位信息.这里就来简述一下,我使用swift获取IOS定位信息的过程. 目录 添加后台定位能力 模拟器 ...

  3. IOS获取系统相簿里的照片

    参考了原作者的这个代码,完成了我的 本地图片的获取,中间过程虽然有点小曲折,也是收获颇多,从中理解了Block的概念,学会了block的使用,同时对ALAsset这个框架页是比较的熟悉,由于我要做的不 ...

  4. iOS开发:获取系统WiFi名称,WiFi列表,WiFi强度,WiFi设置密码,WiFi副标题标签

    前段时间在开发蓝牙功能,蓝牙功能开发结束之后最近又在开发WiFi功能.WiFi功能也算简单,主需要导入使用苹果系统自带的框架即可,仅仅单纯的获取手机当前连接的WiFi名称,或者获取手机系统显示的WiF ...

  5. iOS实现获取系统iTunes音乐的方法示例

    这篇文章主要给大家介绍了关于iOS如何实现获取系统iTunes音乐的相关资料,文中通过示例代码给大家详细介绍了实现的方法,并给大家介绍了MPMediaPickerController的相关知识,对大家 ...

  6. iOS 获取系统相册

    在iOS开发中经常会用到相册的图片,但是原生的UIImagePikerViewDelegate只能选取一张照片进行处理,这样管理起来比较麻烦,所以本次带来获取系统所有相册. 首先建一个继承NSObje ...

  7. IOS Swift 5.0 获取图片-相册、拍照

    一.创建项目 这个很简单,创建好了看下面的就行了 二.添加权限 拍照和获取相册都需要先设置权限 三.布局 实现一个简单的布局,同一个界面,一个按钮 Button,一张图片 ImageView 四.实现 ...

  8. Android获取系统相册图片选中地址,获取手机中的所有图片地址自定义相册

    一.获取手机中的值 1.首先在使用读写sd卡权限 2.获取手机中的所有图片: 注意代码中的getGalleryPhotos(getContentResolver()) 方法获取所有地址 获取所有图片地 ...

  9. 弃掉Android 4.4获取系统图片出错之坑,实现 自定义相册库

    2017年2月份,笔者为了一个项目搞了几天的相册,项目比较急,所以应付了事.昨天突然想起要把这个坑填上,所以"重操旧业"吧. 说到相册,我们首先拥有打开系统文件的权限,其次要获取系 ...

最新文章

  1. MegEngine基本概念
  2. boost::statechart模块实现使用正交状态和 state_downcast 查询正交区域的状态的测试程序
  3. .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理
  4. 如何开启并配置CITRIX Xenserver的SNMP服务
  5. BugkuCTF-MISC题MuMuMisc的简单题
  6. ios双指放大缩小_用PS设计APP过程中改进IOS设计流程的30个秘诀
  7. 排难解惑 为您解开系统无法添加打印机之谜!
  8. matlab 二元函数的画法
  9. Java层Binder使用(ServiceManager)
  10. Tri-training regression, 协同训练回归
  11. html 中加载字体太慢,css字体文件包太大无法引入怎么处理?
  12. 音创服务器系统手动加歌,音创ktv点歌系统的教程
  13. Linux系统开发|QT制作聊天软件实验报告
  14. SPS PPS AAC音频 采样率 比特率
  15. RequestHead详解
  16. 031_onetab
  17. macOS软件历史版本下载
  18. python输入一个英文句子、统计并输出单词数_C语言实现输入多行英文句子然后统计单词数和行数,如何输入?我的代码问题在哪里?...
  19. PHP excel导出(自定义样式,行高,合并单元格等)
  20. Blackbox_exporter概述

热门文章

  1. 雨滴科技系统软件组的分享会
  2. 特征权重的处理与最终排名
  3. 盘点世界科技强国的人工智能+智能制造战略部署
  4. Coolfilter 0.5
  5. PLC 西门子 S7-200smart 搅拌器控制
  6. 数据结构--串、数组、广义表
  7. java return 1 wex5_求大神解决****ERROR****: 子任务 java 执行失败。
  8. word一编辑公式就卡死,点击分数、上下标就卡死
  9. 2020中国区块链产业园月度报告(11月)|链塔智库
  10. 疾病研究:进行性肌营养不良最新研究进展