[SwiftUI 100 天] Instafilter 保存滤镜后的图片
2020/6/1 23:27:18
本文主要是介绍[SwiftUI 100 天] Instafilter 保存滤镜后的图片,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
译自 www.hackingwithswift.com/books/ios-s…
更多内容,欢迎关注公众号 「Swift花园」
喜欢文章?不如来个 🔺💛➕三连?关注专栏,关注我 🚀🚀🚀
用 UIImageWriteToSavedPhotosAlbum() 来保存滤镜后的图片
为了完成这个项目,我们最后需要实现保存按钮:将滤镜处理后的照片保存到用户的相册,以便用户可以进一步编辑照片,或者分享照片。
我在前面解释过,UIImageWriteToSavedPhotosAlbum()
函数可以实现我们要的功能,但需要一些跟 SwiftUI 不太兼容的代码:需要一个继承自 NSObject
的对象,提供以 @objc
标记的回调方法,以及用 #selector
编译器指令指向的方法。
我们要在一个单独的,可重用的类中实现这个目标。请创建一个名叫 ImageSaver.swift 的新 Swift 文件,把导入 Foundation 修改为导入 UIKit,然后提供以下代码:
class ImageSaver: NSObject { func writeToPhotoAlbum(image: UIImage) { UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveError), nil) } @objc func saveError(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) { // save complete } } 复制代码
我们稍后会回到上面的代码做修改。现在需要先确保从用户那里请求到保存照片的权限:我们需要添加一个键到 Info.plist。
- 打开 Info.plist
- 在空白区域右键
- 选择 Add Row
- 选择 “Privacy - Photo Library Additions Usage Description” 作为键名
- 输入 “我们希望保存滤镜照片。” 作为值
接下来是考虑如何利用 ImageSaver
类来保存照片。眼下我们设置 image
属性的方式如下:
if let cgimg = context.createCGImage(outputImage, from: outputImage.extent) { let uiImage = UIImage(cgImage: cgimg) image = Image(uiImage: uiImage) } 复制代码
实际上我们可以直接由 CGImage
生成 SwiftUI Image
视图,之前我也说过之所以借助 UIImage
中转是因为直接从 CGImage
生成需要更多的参数。这个理由当然是真实的,但更重要的原因是:我们需要用到一个 UIImage
,以便传给 ImageSaver
类,而这里正是创建这个对象最好的地方。
把下面这个新属性添加到 ContentView
,以存储中转的 UIImage
:
@State private var processedImage: UIImage? 复制代码
然后,我们要修改 applyProcessing()
方法,暂存 UIImage
以便后续使用:
if let cgimg = context.createCGImage(outputImage, from: outputImage.extent) { let uiImage = UIImage(cgImage: cgimg) image = Image(uiImage: uiImage) processedImage = uiImage } 复制代码
然后是保存按钮中的逻辑:
Button("Save") { guard let processedImage = self.processedImage else { return } let imageSaver = ImageSaver() imageSaver.writeToPhotoAlbum(image: processedImage) } 复制代码
到这里其实我们已经可以收工了,但我们单独做了 ImageSaver
类的目的正是我们可以读取保存是否成功的结果。而这个方法是通过 ImageSaver
里下面这个方法来报告的:
@objc func saveError(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) { // save complete } 复制代码
为了利用这个结果,我们需要将结果传递给 ContentView
。但是,我不希望这个讨厌的 @objc
逃出这个类,所以我们要用闭包来报告成功或者失败 —— 对于 Swift 开发者来说这个解决方案更友好。
首先添加下面这两个属性到 ImageSaver
类,用以表示处理成功和失败的闭包:
var successHandler: (() -> Void)? var errorHandler: ((Error) -> Void)? 复制代码
然后,完善 didFinishSavingWithError
方法,根据成功和失败两种情况分别调用对应的闭包:
if let error = error { errorHandler?(error) } else { successHandler?() } 复制代码
现在,我们就可以在使用 ImageSaver
时这样处理:
let imageSaver = ImageSaver() imageSaver.successHandler = { print("Success!") } imageSaver.errorHandler = { print("Oops: \($0.localizedDescription)") } imageSaver.writeToPhotoAlbum(image: processedImage) 复制代码
尽管代码不一样,但概念和原来在 ImagePicker
里的做法是一样的:我们以对 SwiftUI 更友好的方式封装 UIKit 功能以获取我们想要的行为。更棒的是,这种方式让我们可以获得能够在其他项目中复用的代码 —— 我们实际上构建了一个库!
到此我们已经完成了项目,可以从头尝试应用,导入照片,应用滤镜,保存到相册。干得漂亮!
我的公众号 这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~
这篇关于[SwiftUI 100 天] Instafilter 保存滤镜后的图片的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-10-05Swift语法学习--基于协议进行网络请求
- 2022-08-17Apple开发_Swift语言地标注释
- 2022-07-24Swift 初见
- 2022-05-22SwiftUI App 支持多语种 All In One
- 2022-05-10SwiftUI 组件参数简写 All In One
- 2022-04-14SwiftUI 学习笔记
- 2022-02-23Swift 文件夹和文件操作
- 2022-02-17Swift中使用KVO
- 2022-02-08Swift 汇编 String array
- 2022-01-30SwiftUI3.0页面反向传值