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

如何在SwiftUI中将SDWebImageSwiftUI加载的图片保存至系统相册?

在SwiftUI中使用SDWebImageSwiftUI保存图片到系统相册

我完全懂你的痛点——SwiftUI生态里关于SDWebImageSwiftUI的进阶教程确实不多,大多都是UIKit版本的资料。不过别担心,这里有两种适配你现有代码的可行方案,都能实现点击图片保存到相册的功能:

前置准备:权限配置

首先必须在Info.plist中添加相册写入权限,否则保存会直接失败甚至崩溃:
添加键 NSPhotoLibraryAddUsageDescription,值填类似 "需要访问相册以保存你喜欢的图片" 的描述(根据你的APP场景调整)。

方案一:利用WebImage的加载成功回调获取图片

这种方式最直接,因为SDWebImageSwiftUI的WebImage组件提供了onSuccess回调,加载完成后可以直接拿到UIImage,不需要额外请求:

步骤1:定义保存图片的工具方法

先在你的View里(或者单独的工具类中)实现一个通用的保存方法:

import Photos

func saveImageToPhotos(_ image: UIImage) {
    // 先请求相册权限
    PHPhotoLibrary.requestAuthorization { status in
        guard status == .authorized else {
            // 权限被拒绝时,可以提示用户去设置开启
            print("相册权限未开启,无法保存图片")
            return
        }
        
        // 执行保存操作
        PHPhotoLibrary.shared().performChanges({
            PHAssetChangeRequest.creationRequestForAsset(from: image)
        }) { success, error in
            DispatchQueue.main.async {
                if let error = error {
                    print("图片保存失败:\(error.localizedDescription)")
                    // 这里可以用Alert提示用户失败
                } else if success {
                    print("图片保存成功")
                    // 提示用户保存成功
                }
            }
        }
    }
}

步骤2:修改你的WebImage代码

在现有代码基础上,添加onSuccess缓存图片,再在点击手势中调用保存方法:

import SDWebImageSwiftUI

struct YourView: View {
    let moodboardImages: [YourImageModel] // 你的图片模型数组
    @State private var currentTapImage: UIImage?
    @State private var showSaveAlert = false
    
    var body: some View {
        ForEach(moodboardImages, id: \.self) { imageName in
            WebImage(url: URL(string: imageName.fileLink))
                .resizable()
                .aspectRatio(contentMode: .fit)
                .pinchToZoom()
                // 加载成功时缓存当前图片
                .onSuccess { image, _, _ in
                    currentTapImage = image
                }
                .onTapGesture {
                    guard let image = currentTapImage else { return }
                    saveImageToPhotos(image)
                    showSaveAlert = true
                }
        }
        // 保存成功的提示弹窗
        .alert(isPresented: $showSaveAlert) {
            Alert(title: Text("保存成功"), message: Text("图片已存入系统相册"), dismissButton: .default(Text("确定")))
        }
    }
    
    // 上面的saveImageToPhotos方法放在这里
    func saveImageToPhotos(_ image: UIImage) {
        // ... 实现同上
    }
}

方案二:直接从SDWebImage缓存获取图片

如果不想依赖onSuccess回调,或者需要确保拿到的是最新的缓存图片,可以直接调用SDWebImage的核心API加载图片:

.onTapGesture {
    guard let url = URL(string: imageName.fileLink) else { return }
    // 通过SDWebImageManager加载图片(优先从缓存取,缓存没有则网络请求)
    SDWebImageManager.shared.loadImage(with: url, options: [], progress: nil) { image, _, _, _, _, _ in
        guard let targetImage = image else {
            print("无法获取图片")
            return
        }
        saveImageToPhotos(targetImage)
        DispatchQueue.main.async {
            showSaveAlert = true
        }
    }
}

这种方式的好处是无需提前缓存图片,点击时再触发获取,适合图片列表较长、不想提前缓存所有图片的场景。

注意事项

  • 记得导入必要的框架:import Photosimport SDWebImageSwiftUI(方案二还需要import SDWebImage
  • 权限请求只会弹一次,如果用户拒绝,后续需要引导用户到系统设置开启权限
  • 保存操作是异步的,所有UI相关的提示必须切回主线程(上面的代码已经处理了DispatchQueue.main.async

内容的提问来源于stack exchange,提问作者Hussein

火山引擎 最新活动