SwiftUI从相册选GIF:保留动画、获取时长及完整上传问题
SwiftUI下GIF处理解决方案
1. 显示带动画的GIF
SwiftUI原生Image不支持动画GIF,需通过UIViewRepresentable包装UIKit的UIImageView实现:
struct AnimatedGIFView: UIViewRepresentable { let data: Data func makeUIView(context: Context) -> UIImageView { let imageView = UIImageView() if let gifImage = UIImage.gif(data: data) { imageView.image = gifImage imageView.contentMode = .scaleAspectFit imageView.startAnimating() } return imageView } func updateUIView(_ uiView: UIImageView, context: Context) {} } extension UIImage { static func gif(data: Data) -> UIImage? { guard let source = CGImageSourceCreateWithData(data as CFData, nil) else { return nil } let count = CGImageSourceGetCount(source) var images = [UIImage]() var delays = [Double]() for i in 0..<count { guard let cgImage = CGImageSourceCreateImageAtIndex(source, i, nil) else { continue } images.append(UIImage(cgImage: cgImage)) guard let properties = CGImageSourceCopyPropertiesAtIndex(source, i, nil) as? [String: Any], let gifProperties = properties[kCGImagePropertyGIFDictionary as String] as? [String: Any], let delayTime = gifProperties[kCGImagePropertyGIFDelayTime as String] as? Double else { delays.append(0.1) continue } delays.append(delayTime) } return UIImage.animatedImage(with: images, duration: delays.reduce(0, +)) } }
使用示例:
// 假设已获取GIF原始data AnimatedGIFView(data: gifData) .frame(width: 200, height: 200)
2. 获取GIF总时长
封装解析函数直接从原始数据计算时长:
func getGIFDuration(from data: Data) -> Double { guard let source = CGImageSourceCreateWithData(data as CFData, nil) else { return 0 } let count = CGImageSourceGetCount(source) var totalDuration = 0.0 for i in 0..<count { guard let properties = CGImageSourceCopyPropertiesAtIndex(source, i, nil) as? [String: Any], let gifProperties = properties[kCGImagePropertyGIFDictionary as String] as? [String: Any], let delayTime = gifProperties[kCGImagePropertyGIFDelayTime as String] as? Double else { totalDuration += 0.1 continue } totalDuration += delayTime } return totalDuration }
调用示例:
else if mimeType == "image/gif" { let duration = getGIFDuration(from: data) print("GIF时长:\(duration)秒") // 后续逻辑... }
3. 解决GIF上传末尾缺失问题
问题根源是将原始GIF数据转成UIImage时丢失了格式信息,直接使用PhotosPicker获取的原始data上传即可保留完整数据:
修改你的GIF分支代码:
else if mimeType == "image/gif" { let gifDuration = getGIFDuration(from: data) print("GIF时长:\(gifDuration)") // 直接使用原始数据,跳过UIImage转换 uploadData = data // 存储data用于AnimatedGIFView显示 self.gifData = data do { try await uploadToServer(mime: mimeType) } catch { print(error) } }
在视图中替换原Image(uiImage: image!):
if let gifData = gifData { AnimatedGIFView(data: gifData) .scaledToFit() } else if let image = image { Image(uiImage: image) .resizable() .scaledToFit() }
内容的提问来源于stack exchange,提问作者TheGreatCornholio
相关产品推荐
相关产品推荐

