译自 www.hackingwithswift.com/books/ios-s…
更多内容,欢迎关注公众号 「Swift花园」
喜欢文章?不如来个 🔺💛➕三连?关注专栏,关注我 🚀🚀🚀
生成和缩放二维码
Core Image 可以让我们基于任何字符串输入生成一个二维码,而且过程极快。不过,这里有一个问题:图像的尺寸很小,只包含承载数据必要的像素。要让二维码更好用,需要借助 SwiftUI 的图像插值。因此,在这一步我们要让用户在表单里输入他们的名字和邮件地址,然后用这两条信息生成一个能标识他们的二维码,并且放大这个二维码。
我们已经有一个简单的 MeView 占位,第一个任务是添加一组文本框和对应的字符串绑定。
把保存名称和邮件地址的状态添加到 MeView:
@State private var name = "Anonymous"
@State private var emailAddress = "you@yoursite.com"
至于视图的 body,我们将使用两个大字号的文本框,然后用 spacer 把它们顶到屏幕上方。这里我们要对文本框使用一个小巧但有用的 modifier,它叫 textContentType(),它会告诉 iOS 我们要求用户输入的信息的类型。这可以帮助 iOS 基于用户行为提供自动完成数据的行为,从而提升应用使用体验。
把当前的 body 替换为下面的代码:
NavigationView {
VStack {
TextField("Name", text: $name)
.textContentType(.name)
.font(.title)
.padding(.horizontal)
TextField("Email address", text: $emailAddress)
.textContentType(.emailAddress)
.font(.title)
.padding([.horizontal, .bottom])
Spacer()
}
.navigationBarTitle("Your code")
}
我们要用名称和邮件地址生成二维码。二维码是一块由黑白像素构成的方块,可以通过手机和其他设备来扫描。Core Image 对此提供了专门的滤镜。如果你之前学习过如何使用 Core Image 滤镜,你会发现下面的过程很相似。
首先,我们需要用一个新的 import 来导入 Core Image 内置的滤镜:
import CoreImage.CIFilterBuiltins
其次,我们要用两个属性来分别存储一个激活的 Core Image 上下文和一个 Core Image 的二维码生成器滤镜的实例。把下面两行代码添加到 MeView:
let context = CIContext()
let filter = CIFilter.qrCodeGenerator()
接下来是有趣的部分:制作二维码。如果你还记得,Core Image 滤镜要求我们使用 setValue(_:forKey:) 来设置输入数据,然后把输出的 CIImage 转成 CGImage,再把 CGImage 转成 UIImage。这里的步骤相似,除了以下三点:
- 我们的输入是字符串,但滤镜的输入是
Data,所以我们需要做转换。 - 如果转换因为某种原因失败,我们会返回 SF Symbols 的 “xmark.circle” 图像。
- 如果该图像不能读取 —— 理论上这是有可能的,因为 SF Symbols 是基于字符串的 —— 那么我们将返回一个空的
UIImage。
把下面这个方法添加到 MeView 结构体:
func generateQRCode(from string: String) -> UIImage {
let data = Data(string.utf8)
filter.setValue(data, forKey: "inputMessage")
if let outputImage = filter.outputImage {
if let cgimg = context.createCGImage(outputImage, from: outputImage.extent) {
return UIImage(cgImage: cgimg)
}
}
return UIImage(systemName: "xmark.circle") ?? UIImage()
}
在 SwiftUI 中,通过函数分离功能的做法很奏效,因为这意味着我们放进 body 属性的代码将会尽可能地简单。实际上,我们可以直接使用 generateQRCode(from:) 生成的 Image,然后把它放大到一个合理的尺寸 —— SwiftUI 会确保每一次 name 或者 emailAddress 发生改变时该方法都被调用。
对于传入 generateQRCode(from:) 的字符串,我们将使用用户输入的名称和邮件地址,以换行分隔。这是一个简单实用的格式,在从二维码转换回来时也很容易。
把这个新 Image 视图直接添加到 Spacer 后面:
Image(uiImage: generateQRCode(from: "\(name)\n\(emailAddress)"))
.resizable()
.scaledToFit()
.frame(width: 200, height: 200)
运行代码 —— 你将看到默认的二维码,通过两个文本框的输入,你可以动态地改变二维码。
不过,近距离观察一下二维码 —— 你注意到它是模糊的吗?这是因为 Core Image 生成的是小图像,而 SwiftUI 在放大时尝试平滑像素。
像二维码这样的线条艺术,最好是禁用图像插值,把下面这个 modifier 添加到图像:
.interpolation(.none)
这样二维码就会以比较锐利的方式渲染,因为 SwiftUI 只会复制像素而不会混合像素。对于相机来说,它不关心二维码长啥样,但这样对用户来说比较好看。
我的公众号 这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~