You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS中使用Transferable加载视频时如何监控加载进度?

iOS中使用Transferable加载视频时如何监控加载进度?

嘿,这个问题我太有共鸣了!之前做大视频导入功能的时候,用户一直反馈不知道要等多久,后来摸索出了用PHAssetResourceManager来监控加载进度的方法,给你分享下具体步骤:

核心思路

Transferable本身并没有提供直接的进度回调接口,所以我们需要绕个弯:通过PhotosPicker选中的item标识符拿到对应的PHAsset,再用PHAssetResourceManager来异步加载视频资源——这个方法自带进度回调,刚好能满足我们的需求。

具体实现步骤

  1. 定义状态变量:首先在你的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代码...
}
  1. 处理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
                // 加载完成,后续可以播放视频或者做其他处理
            }
        }
    }
}
  1. 显示加载进度和视频:根据加载状态,在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

火山引擎 最新活动