iOS中使用Transferable加载视频时如何监控加载进度?
iOS中使用Transferable加载视频时如何监控加载进度?
嘿,这个问题我太有共鸣了!之前做大视频导入功能的时候,用户一直反馈不知道要等多久,后来摸索出了用PHAssetResourceManager来监控加载进度的方法,给你分享下具体步骤:
核心思路
Transferable本身并没有提供直接的进度回调接口,所以我们需要绕个弯:通过PhotosPicker选中的item标识符拿到对应的PHAsset,再用PHAssetResourceManager来异步加载视频资源——这个方法自带进度回调,刚好能满足我们的需求。
具体实现步骤
- 定义状态变量:首先在你的View里定义几个用来控制加载状态和进度的变量
import SwiftUI import PhotosUI import Photos import AVKit struct VideoPickerView: View { @State private var selectedItem: PhotosPickerItem? @State private var loadingProgress: Double = 0.0 @State private var isLoading = false @State private var selectedVideoURL: URL? // 剩下的View代码... }
- 处理PhotosPicker的选中事件:当用户选中视频后,通过item的localIdentifier获取PHAsset,再启动带进度的加载流程
PhotosPicker(selection: $selectedItem, matching: .videos) { Text("选择视频") .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(8) } .onChange(of: selectedItem) { newItem in guard let item = newItem else { return } // 重置加载状态 isLoading = true loadingProgress = 0.0 // 通过标识符获取对应的PHAsset let fetchOptions = PHFetchOptions() let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [item.localIdentifier], options: fetchOptions) guard let targetAsset = fetchResult.firstObject else { isLoading = false return } // 获取视频对应的资源对象 guard let videoResource = PHAssetResource.assetResources(for: targetAsset).first(where: { $0.type == .video }) else { isLoading = false return } // 创建临时文件路径用来保存加载后的视频 let tempDirectory = FileManager.default.temporaryDirectory let tempVideoURL = tempDirectory.appendingPathComponent("\(UUID().uuidString).mov") // 设置加载选项,添加进度回调 let requestOptions = PHAssetResourceRequestOptions() requestOptions.progressHandler = { progress, _, _, _ in // 回到主线程更新UI DispatchQueue.main.async { self.loadingProgress = progress } } // 开始异步加载视频资源 PHAssetResourceManager.default().writeData(for: videoResource, toFile: tempVideoURL, options: requestOptions) { error in DispatchQueue.main.async { self.isLoading = false if let loadError = error { print("视频加载失败:\(loadError.localizedDescription)") // 这里可以给用户显示错误提示 } else { self.selectedVideoURL = tempVideoURL // 加载完成,后续可以播放视频或者做其他处理 } } } }
- 显示加载进度和视频:根据加载状态,在View里展示进度条或者视频播放器
var body: some View { VStack(spacing: 20) { // 选择按钮 PhotosPicker(selection: $selectedItem, matching: .videos) { Text("选择视频") .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(8) } // 加载进度展示 if isLoading { VStack(spacing: 10) { ProgressView(value: loadingProgress) .progressViewStyle(.linear) .padding(.horizontal) Text("正在加载:\(Int(loadingProgress * 100))%") .font(.caption) } } // 加载完成后显示视频 if let videoURL = selectedVideoURL { VideoPlayer(player: AVPlayer(url: videoURL)) .frame(height: 300) .cornerRadius(12) } } .padding() }
注意事项
- 别忘了在
Info.plist里添加照片库权限描述:NSPhotoLibraryUsageDescription,否则App会因为权限问题崩溃 - 临时文件可以在使用完成后自行删除,避免占用存储空间
备注:内容来源于stack exchange,提问作者zumzum




