iOS Swift:如何让UIImagePickerController仅展示特定时长以内的视频
嘿,这个需求我之前做项目的时候刚好碰到过!系统自带的UIImagePickerController本身并没有直接提供按视频时长筛选的配置项,不过咱们有两种靠谱的方案来实现:一种是提前用PhotoKit筛选出符合时长要求的视频,做个自定义选择界面;另一种是用系统picker,等用户选完再校验时长。下面给你详细拆解:
方案一:用PhotoKit预筛选(推荐,体验更流畅)
这种方式能让用户在选择界面就只看到符合时长的视频,避免选完才发现不符合的尴尬。步骤如下:
- 先导入PhotoKit框架
在你的ViewController顶部加上:
import Photos
- 申请相册访问权限
这是必须的,先处理权限逻辑:
func requestPhotoPermission() { PHPhotoLibrary.requestAuthorization { status in DispatchQueue.main.async { switch status { case .authorized: // 权限通过,开始获取符合条件的视频 self.fetchShortVideos(maxDuration: 10) // 这里设置你要的最大时长,比如10秒 case .denied, .restricted: // 提示用户开启权限 let alert = UIAlertController(title: "需要相册权限", message: "请在设置中开启相册权限以选择视频", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "知道了", style: .default)) self.present(alert, animated: true) default: break } } } }
- 筛选符合时长的视频资产
用PHFetchOptions设置过滤条件,只拉取时长小于指定值的视频:
func fetchShortVideos(maxDuration: TimeInterval) { let fetchOptions = PHFetchOptions() // 设置过滤条件:时长小于maxDuration秒 fetchOptions.predicate = NSPredicate(format: "duration < %f", maxDuration) // 指定只获取视频类型 fetchOptions.mediaTypes = [.video] // 按创建时间倒序排列,最新的在前 fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] // 获取符合条件的视频资产 let videoAssets = PHAsset.fetchAssets(with: fetchOptions) // 接下来你可以用这些assets来搭建自定义的选择界面,比如用UICollectionView展示缩略图 // 举个获取缩略图的例子: let imageManager = PHImageManager.default() let targetSize = CGSize(width: 150, height: 150) // 缩略图大小 videoAssets.enumerateObjects { asset, _, _ in imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: nil) { image, _ in // 拿到缩略图image,加到你的数据源里 } } }
- 用户选中后获取视频文件
当用户在自定义界面选中某个asset时,用PHImageManager获取视频的URL:
func getVideoURL(from asset: PHAsset, completion: @escaping (URL?) -> Void) { let options = PHVideoRequestOptions() options.isNetworkAccessAllowed = true // 允许从iCloud获取 PHImageManager.default().requestAVAsset(forVideo: asset, options: options) { avAsset, _, _ in guard let urlAsset = avAsset as? AVURLAsset else { completion(nil) return } completion(urlAsset.url) } }
方案二:系统Picker选后校验(快速实现)
如果不想自定义界面,用系统的UIImagePickerController也可以,只是需要在用户选完后检查时长:
- 配置并弹出系统Picker
记得导入MobileCoreServices框架:
import MobileCoreServices func showVideoPicker() { let picker = UIImagePickerController() picker.sourceType = .photoLibrary // 指定只选择视频 picker.mediaTypes = [kUTTypeMovie as String] picker.delegate = self present(picker, animated: true) }
- 实现代理方法,校验时长
要确保你的ViewController遵守UIImagePickerControllerDelegate和UINavigationControllerDelegate协议:
extension YourViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate { func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { picker.dismiss(animated: true) // 获取视频URL guard let videoURL = info[.mediaURL] as? URL else { return } // 加载视频资产,获取时长 let asset = AVAsset(url: videoURL) asset.loadValuesAsynchronously(forKeys: ["duration"]) { var error: NSError? let status = asset.statusOfValue(forKey: "duration", error: &error) DispatchQueue.main.async { switch status { case .loaded: let duration = asset.duration.seconds if duration < 10 { // 这里设置你的最大时长 // 符合条件,处理视频 self.handleSelectedVideo(url: videoURL) } else { // 时长过长,提示用户 let alert = UIAlertController(title: "视频时长过长", message: "请选择时长小于10秒的视频", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "重新选择", style: .default, handler: { _ in self.showVideoPicker() })) alert.addAction(UIAlertAction(title: "取消", style: .cancel)) self.present(alert, animated: true) } case .failed, .cancelled: // 加载失败,提示用户 let alert = UIAlertController(title: "错误", message: "无法获取视频时长", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) self.present(alert, animated: true) default: break } } } } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { picker.dismiss(animated: true) } }
额外注意点
- 不管哪种方案,都要在
Info.plist中添加NSPhotoLibraryUsageDescription权限描述,不然App会直接崩溃。 - 如果要支持iCloud中的视频,记得在PHVideoRequestOptions中设置
isNetworkAccessAllowed = true,并可以添加加载中的提示状态。
内容的提问来源于stack exchange,提问作者Geoff H
相关产品推荐
相关产品推荐

