美文网首页
iOS 相册的使用

iOS 相册的使用

作者: Minoz_min | 来源:发表于2023-10-16 16:56 被阅读0次

    1 访问相册功能

    1.1 配置相关

    1.在Info.plist文件中设置相册权限

    <key>NSPhotoLibraryAddUsageDescription</key>
    <string>允许此权限才能使用添加照片功能</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>允许此权限才能使用相册功能</string>
    

    2.使用PHPhotoLibrary 的API和UI组件,需要导入以下2个头文件

    import Photos
    import PhotosUI
    

    1.2 iOS 14以后新新增选择照片...权限

    image.png

    1.2.1 PHAuthorizationStatus.limited,每次冷启动都会弹窗提示

    image.png
    • Info.plist文件中设置PHPhotoLibraryPreventAutomaticLimitedAccessAlertYES可关闭弹窗
    <key>PHPhotoLibraryPreventAutomaticLimitedAccessAlert</key>
    <true/>
    

    1.2.2 手动触发选择更多照片弹窗

    PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: self)
    
    选择照片....jpg

    也可以在设置->照片中编辑所选照片

    设置->照片.jpg

    1.3 获取相册权限和请求相册权限

    1. iOS 14.0包括以上使用
    @available(iOS 14, *)
    open class func authorizationStatus(for accessLevel: PHAccessLevel) -> PHAuthorizationStatus
    
    @available(iOS 14, *)
    open class func requestAuthorization(for accessLevel: PHAccessLevel, handler: @escaping (PHAuthorizationStatus) -> Void)
    

    相册访问方式新增PHAccessLevel

    • addOnly 只读
    • readWrite 读写

    PHAuthorizationStatus 权限新增.limited,请求权限在readWrite时生效

         func checkPHAuthorization(_ handler: @escaping ((Bool) -> Void)) {
            // 获取相册权限
            let authStatus = PHPhotoLibrary.authorizationStatus(for: .readWrite)
            
            switch (authStatus) {
            // 允许访问所有照片
            case .authorized:
                handler(true)
            // 选择照片...
            case .limited:
                handler(true)
            // 首次弹窗权限未授权
            case .notDetermined:
                // 请求相册权限
                PHPhotoLibrary.requestAuthorization(for: .readWrite) { status in
                    DispatchQueue.main.async {
                        switch status {
                        case .authorized, .limited:
                            handler(true)
                            
                        default:
                            handler(false)
                        }
                    }
                }
            // 拒绝等
            default:
                handler(false)
            }
        }
    
    1. iOS 14.0以下使用
    @available(iOS, introduced: 8, deprecated: 100000)
    open class func authorizationStatus() -> PHAuthorizationStatus
    
    @available(iOS, introduced: 8, deprecated: 100000)
    open class func requestAuthorization(_ handler: @escaping (PHAuthorizationStatus) -> Void)
    
       func checkPHAuthorization(_ handler: @escaping ((Bool) -> Void)) {
            let authStatus = PHPhotoLibrary.authorizationStatus()
            
            switch (authStatus) {
            // 允许访问所有照片,选择照片...
            case .authorized:
                handler(true)
                
            case .notDetermined:
                PHPhotoLibrary.requestAuthorization { status in
                    DispatchQueue.main.async {
                        switch status {
                        case .authorized:
                            handler(true)
                            
                        default:
                            handler(false)
                        }
                    }
                }
            default:
                handler(false)
            }
        }
    

    注意:
    未设置PHAccessLevel时,选择照片...的权限为.authorized,设置了readWrite时权限为. limited

    1.4 单选,使用系统API:UIImagePickerController

    let imagePickerController = UIImagePickerController()
    imagePickerController.modalPresentationStyle = .fullScreen
    imagePickerController.delegate = self
    // 是否允许编辑
    imagePickerController.allowsEditing = true
    

    需要遵守UINavigationControllerDelegateUIImagePickerControllerDelegate协议

    extension LITBImagePickerController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        // 取消
        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            picker.dismiss(animated: true, completion: nil)
        }
        // 选择照片
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            var fileImage: UIImage?
            
            if picker.allowsEditing {
                if let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
                    fileImage = image
                }
            } else {
                if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
                    fileImage = image
                }
            }
            
            if let img = fileImage {
                systemHandler?(img)
            }
            
            picker.dismiss(animated: true, completion: nil)
        }
    }
    

    1.5 多选,多选UI需要自己实现,相关API

    1.5.1 获取缩略图

        /// 获取缩略图
        /// - Parameters:
        ///   - asset: PHAsset
        ///   - imageSize: 图片大小
        ///   - completion: 获取系统图片
        func getThumbnailWithAsset(asset: PHAsset, imageSize: CGSize, completion: @escaping ((UIImage?) -> Void)) {
            let requestOptions = PHImageRequestOptions()
            requestOptions.resizeMode = .fast
            
            let scale = UIScreen.main.scale
            let size = CGSize(width: imageSize.width * scale, height: imageSize.height * scale)
            
            PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: .aspectFill, options: requestOptions) { image, info in
                completion(image)
            }
        }
    

    1.5.2 获取原图

        /// 获取原图
        /// - Parameters:
        ///   - asset: PHAsset
        ///   - isSync: 开启同步执行,默认是flase(异步执行)
        ///   - progressHandler: 加载图片进度回调
        ///   - completion: 获取图片回调
        func getOriginalPhotoWithAsset(asset: PHAsset, isSync: Bool = false, progressHandler: ((Double?, Error?) -> Void)?, completion: @escaping ((UIImage?) -> Void)) {
            let requestOptions = PHImageRequestOptions()
            requestOptions.resizeMode = .fast
            requestOptions.isSynchronous = isSync
            
            requestOptions.progressHandler = { (progress, error, stop, info) in
                DispatchQueue.main.async {
                    progressHandler?(progress, error)
                }
            }
            
            // 该方法是异步执行,会回调多次,当isSynchronous设为true时,deliveryMode属性就会被忽略,并被当作.HighQualityFormat来处理。
            PHImageManager.default().requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFill, options: requestOptions) { image, info in
                /*
                 info?[PHImageResultIsDegradedKey]
                 
                 PHImageResultIsDegradedKey 1表示低质量图片,0是高质量图片
                 
                 设置isSynchronous为true时,阻塞线程,直到图片被准备好或发生错误时才会回调,回调一次
                 */
                completion(image)
            }
        }
    

    1.5.3 获取相薄

        /// 获取相簿列表
        func getAlbumList() -> [AlbumItem] {
            var items: [AlbumItem] = []
            
            // 获取系统的相机相册
            let smartOptions = PHFetchOptions()
            let smartAlbums = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumRegular, options: smartOptions)
            items.append(contentsOf: convertCollection(collection: smartAlbums))
            
            // 获取用户创建的相册
            let userCustomCollections = PHFetchOptions()
            let userCustomAlbums = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .albumRegular, options: userCustomCollections)
            items.append(contentsOf: convertCollection(collection: userCustomAlbums))
            
            return items
        }
        
        /// 转化处理获取到的相簿
        private func convertCollection(collection: PHFetchResult<PHAssetCollection>) -> [AlbumItem] {
            var items: [AlbumItem] = []
            
            // 获取转化前相簿内容的图片
            collection.enumerateObjects { object, index, stop in
                let resultsOptions = PHFetchOptions()
                // 按照创建时间,进行倒序
                resultsOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
                resultsOptions.predicate = NSPredicate(format: "mediaType=%d", PHAssetMediaType.image.rawValue)
                
                let assetsFetchResult = PHAsset.fetchAssets(in: object, options: resultsOptions)
                
                // 过滤隐藏相册,最近删除相册(1000000201)
                if object.assetCollectionSubtype == .smartAlbumAllHidden || object.assetCollectionSubtype.rawValue > 1000000000 { return }
                
                if assetsFetchResult.count > 0 {
                    let item = AlbumItem(title: object.localizedTitle ?? "Unnamed", fetchResult: assetsFetchResult)
                    
                    // 最近项目显示在最前面
                    if object.assetCollectionSubtype == .smartAlbumUserLibrary {
                        items.insert(item, at: 0)
                    } else {
                        items.append(item)
                    }
                }
            }
            
            return items
        }
    

    1.5.4 监听相册变化,PHAuthorizationStatus.limited时需要监听

    class LITBSelectImagesViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            // 开始监听
            PHPhotoLibrary.shared().register(self)
        }
        
        deinit {
            // 结束监听
            PHPhotoLibrary.shared().unregisterChangeObserver(self)
        }
    }
    
    extension LITBSelectImagesViewController: PHPhotoLibraryChangeObserver {
        func photoLibraryDidChange(_ changeInstance: PHChange) {
            // selectedFetchResult: PHFetchResult<PHAsset> 为当前选中的相薄
            guard let selectedFetchResult = controller.selectedFetchResult else { return }
            
            DispatchQueue.main.async {
                guard let changes = changeInstance.changeDetails(for: selectedFetchResult) else { return }
                // 获取更新的相册,更新UI
                self.controller.getAllAssets(assets: changes.fetchResultAfterChanges) {
                    self.collectionView.reloadData()
                }
            }
        }
    }
    

    2 使用PHPickerViewController

    • 不需要设置相册访问权限
    • 不能编辑照片
    • 不支持查看大图
    import UIKit
    import PhotosUI
    import Photos
    
    class ViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
        }
    
        @IBAction func onSingle(_ sender: Any) {
            showPikcer(limitCount: 1)
        }
        
        @IBAction func onMultiple(_ sender: Any) {
            showPikcer(limitCount: 9)
        }
        
        func showPikcer(limitCount: Int) {
            var config = PHPickerConfiguration()
            // 可选择的资源数量,0表示不设限制,默认为1
            config.selectionLimit = limitCount
            // 可选择的资源类型,只显示图片(注:images包含livePhotos)
            config.filter = .images
            // 显示livePhotos和视频(注:livePhotos不包含images)
    //        config.filter = .any(of: [.livePhotos, .videos])
            // 如果要获取视频,最好设置该属性,避免系统对视频进行转码
            config.preferredAssetRepresentationMode = .current
            
            let pickerVC = PHPickerViewController(configuration: config)
            pickerVC.delegate = self
            present(pickerVC, animated: true)
        }
    }
    
    extension ViewController: PHPickerViewControllerDelegate {
        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            // 关闭页面
            dismiss(animated: true)
            
            // 取消选择也会触发代理方法,会返回空的results
            guard !results.isEmpty else { return }
            
            results.forEach { result in
                // 判断类型是否为UIImage
                if result.itemProvider.canLoadObject(ofClass: UIImage.self) {
                    // 获取图片
                    result.itemProvider.loadObject(ofClass: UIImage.self) { itemProvider, error in
                        // 回调结果在异步线程,展示时需要切换到主线程
                        if let image = itemProvider as? UIImage {
                            DispatchQueue.main.async {
                                print("---:", image)
                            }
                        }
                    }
                }
            }
        }
    }
    
    最多选择9张照片.jpg

    更多PHPickerViewController参考资料:https://juejin.cn/post/6881513652176814093

    相关文章

      网友评论

          本文标题:iOS 相册的使用

          本文链接:https://www.haomeiwen.com/subject/dguxidtx.html