版本记录
版本号 | 时间 |
---|---|
V1.0 | 2022.02.23 星期三 |
前言
今天翻阅苹果的API文档,发现多了一个框架SwiftUI,这里我们就一起来看一下这个框架。感兴趣的看下面几篇文章。
1. SwiftUI框架详细解析 (一) —— 基本概览(一)
2. SwiftUI框架详细解析 (二) —— 基于SwiftUI的闪屏页的创建(一)
3. SwiftUI框架详细解析 (三) —— 基于SwiftUI的闪屏页的创建(二)
4. SwiftUI框架详细解析 (四) —— 使用SwiftUI进行苹果登录(一)
5. SwiftUI框架详细解析 (五) —— 使用SwiftUI进行苹果登录(二)
6. SwiftUI框架详细解析 (六) —— 基于SwiftUI的导航的实现(一)
7. SwiftUI框架详细解析 (七) —— 基于SwiftUI的导航的实现(二)
8. SwiftUI框架详细解析 (八) —— 基于SwiftUI的动画的实现(一)
9. SwiftUI框架详细解析 (九) —— 基于SwiftUI的动画的实现(二)
10. SwiftUI框架详细解析 (十) —— 基于SwiftUI构建各种自定义图表(一)
11. SwiftUI框架详细解析 (十一) —— 基于SwiftUI构建各种自定义图表(二)
12. SwiftUI框架详细解析 (十二) —— 基于SwiftUI创建Mind-Map UI(一)
13. SwiftUI框架详细解析 (十三) —— 基于SwiftUI创建Mind-Map UI(二)
14. SwiftUI框架详细解析 (十四) —— 基于Firebase Cloud Firestore的SwiftUI iOS程序的持久性添加(一)
15. SwiftUI框架详细解析 (十五) —— 基于Firebase Cloud Firestore的SwiftUI iOS程序的持久性添加(二)
16. SwiftUI框架详细解析 (十六) —— 基于SwiftUI简单App的Dependency Injection应用(一)
17. SwiftUI框架详细解析 (十七) —— 基于SwiftUI简单App的Dependency Injection应用(二)
18. SwiftUI框架详细解析 (十八) —— Firebase Remote Config教程(一)
19. SwiftUI框架详细解析 (十九) —— Firebase Remote Config教程(二)
20. SwiftUI框架详细解析 (二十) —— 基于SwiftUI的Document-Based App的创建(一)
21. SwiftUI框架详细解析 (二十一) —— 基于SwiftUI的Document-Based App的创建(二)
22. SwiftUI框架详细解析 (二十二) —— 基于SwiftUI的AWS AppSync框架的使用(一)
23. SwiftUI框架详细解析 (二十三) —— 基于SwiftUI的AWS AppSync框架的使用(二)
24. SwiftUI框架详细解析 (二十四) —— 基于SwiftUI的编辑占位符的使用(一)
25. SwiftUI框架详细解析 (二十五) —— 基于SwiftUI的编辑占位符的使用(二)
26. SwiftUI框架详细解析 (二十六) —— 基于SwiftUI和Xcode12的Multiplatform App的搭建(一)
27. SwiftUI框架详细解析 (二十七) —— 基于SwiftUI和Xcode12的Multiplatform App的搭建(二)
开始
首先看下主要内容:
了解如何将
iPhone
摄像头中的文本捕捉到您的SwiftUI
应用程序中,以便您的用户可以更快速、更轻松地输入数据。内容来自翻译。
接着看下写作环境:
Swift 5.5, iOS 15, Xcode 13
下面就是正文了
您的 iPhone
相机可以让您捕捉风景、人物和事件,但它也是一个有用的信息收集工具。您会看到一张音乐会海报或您需要的服务的广告或一家看起来很有趣的餐厅,然后拍照。稍后,您在搜索引擎或新联系人中键入或说出照片中的一些文本(URL、日期、电话号码)。
但是键盘或语音输入很容易出错,要是您可以从照片或直接从相机视图中复制和粘贴文本该多好?更好的是,要是您可以将照片或相机视图中的文本直接扫描到您的应用程序中会怎样?热烈欢迎 iOS 15
实时文本!
在本教程中,您将学习如何将 iPhone 相机中的文本捕获到您的 SwiftUI
应用程序中,让您的用户更快速、更轻松地输入数据。
注意:您应该熟悉使用
SwiftUI、Swift
和Xcode
开发 iOS 应用程序。您需要 Xcode 13 和运行 iOS 15 的 iPhone。您的 iPhone 必须是 2018 年或之后生产的,因此它具有A12
(或更高版本)神经引擎(Neural Engine)
。其首选语言列表必须至少包括以下语言之一:英语、西班牙语、中文、法语、意大利语、德语、葡萄牙语。并检查您所在地区的此列表check this list for your region。
iOS 15 Live Text
精彩的新 iOS 15
实时文本功能开箱即用,并且仅适用于上述注释中列出的语言和地区。
您需要一部新的 (2018+) iPhone,配备 A12 或更高版本的神经引擎。 Live Text
使用 Apple 的 Vision
机器学习模型,该模型需要神经引擎。
Live Text
适用于iPhone XS, iPhone XR and later。 这些 iPhone
不支持实时文本:iPhone SE(第一代)、iPhone 6S、iPhone 6S Plus、iPhone 7、iPhone 7 Plus 和 iPhone X
。
Live Text
可以在 2018 年或之后的 iPad
上的照片中使用,但在 iPad 相机上则不行not iPad Camera。 这篇文章是关于使用带有相机的实时文本,所以它只是关于 iPhone。
现在拿起你的 iPhone 并确保 Live Text
已打开:在 Settings
中,打开 Camera ▸ Live Text 和 General ▸ Language & Region ▸ Live Text
:
注意:如果您没有看到这些设置,则您的 iPhone 没有神经引擎。 如果您正在寻找购买 iPhone 13 的借口,那这个接口就不错!
1. Live Text in Photos
实时文本检测照片和Camera ▸ Photo
取景器中的文本。 在本教程中,您将使用 iPhone 的相机。 但首先,看看它在您现有的照片上有多棒。 在手持相机视图中没有移动的图像上使用实时文本也更容易练习。
打开照片并找到包含一些文字的照片,尤其是 URL、电话号码、电子邮件或街道地址。
我有这张我在yarn expo
上拍的照片,作为提醒我以后想查找的供应商。
我点击了Live Text
按钮(取景器正方形中的三行); 它变成了蓝色。 然后我点击了 tarndie.com
,他们的网页在 Safari
中打开了!
如果您的照片中有地图地址,点击它会打开地图Maps
。 点击电话号码会显示呼叫、发送消息、FaceTime
等常用菜单。
如果有一个电子邮件地址,点击它会在您的电子邮件应用程序中打开一条新消息。
如果您想从不允许您选择文本的应用程序中复制文本,只需截取屏幕截图并打开预览照片:
注意:感谢
Harshil Shah
发推文tweeting。 截屏来自Chris Wu
的Museum Shuffle。
Live Text
在相机Camera
应用程序中的原理相同,但您需要稳定的手。 如果你不能让它专注于你想要的东西,只需拍张照片,然后使用Live Text
。
现在继续阅读以了解如何在应用程序中使用Live Text
。
打开demo文件夹,在 starter
文件夹中打开 WaitForIt
项目。 这是一个简单的应用程序,您可以在其中记录您需要等待某人生日的时间。 它使用新的 Date.RelativeFormatStyle
方法 relative(presentation:unitsStyle:)
。
要获得相机输入,您必须在您的 iPhone-with-Neural-Engine
上运行此应用程序。
2. Build and Run on Your Device
使用电线将 iPhone 连接到 Mac。 在target
的 Signing & Capabilities
选项卡中,自定义 Bundle Identifier
并设置 Team
。
从运行目标菜单中选择您的 iPhone,然后构建并运行。
以这种格式写下或输入您的姓名和生日:
相机输入适用于手写,但根据我的经验,书写需要非常清晰,更像是仔细打印而不是草书。
点击 +
按钮。 在 Add Person
视图中,点击 Name
的text field
,然后再次点击它以显示 Scan Text
按钮:
注意:您可能只会在粘贴按钮旁边看到扫描按钮图标。 这往往会在您使用扫描按钮几次之后发生,并且系统决定您不再需要文本标签。
点击此按钮打开相机并将相机对准您的姓名和生日文本:
检测到的文本周围出现括号,检测到的文本也出现在text field
中。 括号和text field
文本可以随着您的手移动相机而改变,检测不同数量的文本。
您可以点击以指示您希望相机聚焦的位置,您可以在相机视图上向上拖动以放大它:
如果您只想要部分检测到的文本,请点击右下角的扫描按钮以显示文本:
然后点击或滑动以从检测到的文本中选择您想要的内容:
然后点击Insert
以接受您选择的文本:
现在以相同的方式添加生日文本,然后点击Done
返回列表视图:
3. It’s Magic
现在查看 AddPersonView.swift
中的代码。代码中绝对没有关于从相机扫描文本的内容。此功能是 iOS 15
的一部分,您可以在任何可编辑的视图中免费使用。
那么这篇文章的其余部分是什么?改善用户体验的几个功能:
- 针对特定文本内容类型(如日期、电话号码和电子邮件地址)过滤相机输入。
- 显示
Scan Text
按钮以使您的用户可以看到相机输入功能。
您还可以实现Scan Text
按钮来创建不是text field or text view
的可编辑视图,例如WWDC presentation。
Filtering Text Content Types
您可能对这种扫描、点击过程有点不知所措。如果您的应用正在寻找特定格式的信息——URL、日期、电子邮件或电话号码——您希望相机仅“看到”相关文本而忽略其余文本。
您的应用程序可能已经指定了键盘到了类型,以便用户更方便地输入数字或电子邮件地址。也许您还指定文本内容类型来指导键盘的建议和自动填充。
好消息:您可以使用文本内容类型来过滤相机文本输入!
1. Filtering Date Text
首先将此修饰符添加到 AddPersonView.swift
中的second (Birthday) TextField
:
.textContentType(.dateTime)
这告诉系统您希望输入文本是某种形式的日期、时间或持续时间。 神经引擎的Vision
模型将使用此提示来过滤相机的日期或时间文本输入。
有几种与人名相关的文本内容类型,那么为什么不修改Name text field
呢? 好吧,目前,相机输入仅适用于少数文本内容类型。
在属性检查器文本内容类型菜单中的所有Text Content Type
中,相机当前仅过滤 fullStreetAddress、telephoneNumber、emailAddress、URL、shippingTrackingNumber、flightNumber
和 dateTime
。
好的,是时候看看你的修饰符是否有帮助。
在您的设备上构建并运行,然后点击 +
按钮。 在Add Person
视图中,点击Birthday text field
,然后再次点击它:
注意:与
Scan Text
按钮标签一样,您可能会看到Paste | scan-button-icon
图标而不是Scan Date or Time
。 日期过滤器仍然有效。
现在相机只突出显示与日期或时间相关的文本:
和以前一样,任何检测到的日期或时间文本都会立即出现在text field
中。您仍然必须点击Insert
以接受文本。
从相机加速文本输入的好方法!
注意:我添加了一个电子邮件地址来试用该文本内容类型。如果将
dateTime
更改为emailAddress
,相机将只关注电子邮件地址。
Display a Camera Button
到目前为止,所有内容都内置在 iOS 15
中。但您也可以将相关代码添加到您的应用程序中。
例如,为了让您的用户更容易看到相机输入功能,您可以添加一个按钮来设置整个神奇过程。一旦您知道魔法是如何发生的,您就可以使用它将来自相机的文本扫描到不是text fields or text views
的视图中。
1. Magic Method
新方法 captureTextFromCamera(responder:identifier:)
是魔法的关键,它在您的应用调用此方法启动相机时开始。响应者必须遵循 UIResponder
和 UIKeyInput
。响应者使用 UIKeyInput
方法来实现简单的文本输入。
哦,UI
前缀……确实,captureTextFromCamera(responder:identifier:)
是一个 UIAction
,所以你需要一个 UIView
来调用它。您将创建一个 AddPersonView
可以显示的 UIButton
。您将将此按钮的操作设置为 captureTextFromCamera(responder:identifier:)
。并且动作的responder
将从相机捕获的任何文本传递到 AddPersonView
中的 TextField
。
2. UIViewRepresentable
要创建可以在 SwiftUI
应用程序中使用的 UIView
,您需要构建一个符合 UIViewRepresentable
的结构。
注意:在 SwiftUI Apprentice 和 SwiftUI by Tutorials中了解更多关于
UIViewRepresentable
的信息。
首先,创建一个新的 Swift
文件并将其命名为 ScanButton
。在这个新文件中,将 import Foundation
替换为以下代码:
import SwiftUI
struct ScanButton: UIViewRepresentable {
func makeUIView(context: Context) -> UIButton {
let button = UIButton()
return button
}
func updateUIView(_ uiView: UIButton, context: Context) { }
}
为了遵循 UIViewRepresentable
,ScanButton
必须实现 makeUIView(context:)
和 updateUIView(_:context:)
。
在这个最小形式中,makeUIView(context:)
只是创建了一个 UIButton
。 AddPersonView
不会更新按钮,所以 updateUIView(_:context:)
是空的。
3. Coordinator
点击可以捕获 ScanButton
必须传递给 AddPersonView
的文本的按钮。 要将数据从 UIView
传输到 SwiftUI View
,ScanButton
需要一个coordinator
。
在 ScanButton
中添加此代码:
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: UIResponder, UIKeyInput {
let parent: ScanButton
init(_ parent: ScanButton) { self.parent = parent }
var hasText = false
func insertText(_ text: String) { }
func deleteBackward() { }
}
ScanButton
在 makeUIView(context:)
之前调用 makeCoordinator()
并将 Coordinator
对象存储在context.coordinator
中。
行为captureTextFromCamera(responder:identifier:)
需要符合 UIKeyInput
的 UIResponder
参数,因此您将 Coordinator
设为 UIResponder
的子类并添加 UIKeyInput
协议。 实现此协议将使协调器能够控制文本输入。
UIKeyInput
要求您提供 hasText、insertText(_:)
和 deleteBackward()
。 您需要相机输入而不是键盘输入,因此您只需实现 insertText(_:)
即可处理相机输入。 hasText
的值无关紧要,所以设置为 false
。 而 deleteBackward()
不需要做任何事情。
Coordinator
的目的是将文本从相机传回调用 ScanButton
的 SwiftUI
视图,因此 ScanButton
需要绑定到 SwiftUI
视图中的 String
属性。
在 ScanButton
顶部添加此属性:
@Binding var text: String
AddPersonView
会将 $name
或 $birthday
传递给 ScanButton
。
现在您可以完成 Coordinator
的设置。 将此行添加到 insertText
:
parent.text = text
是的,这确实是 Coordinator
需要做的所有事情!
4. Setting the Button’s Action
现在回到制作你的 UIButton
。
在 makeUIView(context:)
中,将button
声明替换为以下内容:
let textFromCamera = UIAction.captureTextFromCamera(
responder: context.coordinator,
identifier: nil)
let button = UIButton(primaryAction: textFromCamera)
您创建一个 UIAction
以使用您的 Coordinator
对象作为responder
从相机捕获文本。
然后,使用此操作action
作为主要操作创建按钮。 这会将按钮的标题和图像设置为操作action
的标题和图像。
那么这看起来像什么? 设置预览以查看…
在 ScanButton
下方添加此代码:
struct ScanButton_Previews: PreviewProvider {
static var previews: some View {
ScanButton(text: .constant(""))
.previewLayout(.sizeThatFits)
}
}
出现预览画布。
如果该应用程序仍在您的手机上运行,请停止它。
在运行目标菜单中选择一个模拟器,然后按 Option-Command-P
或单击 Resume
以查看:
sizeThatFits
实际上是所选模拟器的全屏尺寸。 您将在 AddPersonView
中通过为其frame
设置宽度和高度值来修剪它。
5. Adding ScanButton to AddPersonView
现在回到 AddPersonView.swift
。 有两种方法可以在这里使用 ScanButton
。
一种方法是在text field
旁边显示按钮。
用这个 HStack
替换 Name TextField
:
HStack {
TextField("Name", text: $name)
ScanButton(text: $name)
.frame(width: 100, height: 56, alignment: .leading)
}
您将绑定传递给 name
,设置按钮的宽度和高度,并确保操作的图像位于按钮frame
的leading
边缘。
刷新预览以查看您的按钮:
显示按钮的另一种方法是在键盘工具栏中。
将此修饰符添加到Birthday TextField
:
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
ScanButton(text: $birthday)
}
}
这一次,您将绑定传递给birthday
。 工具栏约束按钮的frame
,您插入 Spacer()
以将按钮推到工具栏的后沿。
运行实时预览,然后点击Birthday text field
以在键盘工具栏中查看您的按钮:
注意:实际上,此屏幕截图来自模拟器。 键盘不会出现在
Xcode 13
的实时预览中。
现在,关闭实时预览并在您的设备上运行该应用程序以试用这两个按钮。
您的 ScanButton
的行为与内置扫描按钮不完全相同。相机检测到的文本不会立即出现在text field
中。此外,Birthday Scan Text
按钮会忽略text field
的文本内容类型设置。至少,Xcode 13
和 iOS 15
的 RC
版本会发生这种情况。您可能会在更高版本的 Xcode/iOS
中看到更好的结果。
双击Birthday text field
,然后使用内置的扫描按钮,仍然会过滤日期文本。
Scan Text Into Title
ScanButton
可帮助您的用户了解此输入选项,但这并不是必需的。一旦用户了解了相机输入,他们就会期望将它与任何text field or text view
一起使用。这很有效,不需要你的帮助。
如果您想将文本扫描进label
之类的东西怎么办?没问题,ScanButton
不关心它在哪里插入捕获的文本:只需给它一个 String
变量来插入文本,然后调用视图可以在任何它想要的地方使用这个 String
值。
例如,您可以使用扫描文本来更改 AddPersonView
的导航标题。
在 ScanButton
中,添加此 @Binding
:
@Binding var title: String
在insertText(_:)
中,加下面这行:
parent.title = "Add \(text)"
在previews
中,将 ScanButton(text:)
替换为:
ScanButton(text: .constant(""), title: .constant(""))
现在,AddPersonView.swift
警告参数title
缺少参数。
将此@State
属性添加到 AddPersonView
:
@State private var title = "Add a Person"
在 Name text field
的 HStack
中,将 ScanButton(text:)
替换为以下行:
ScanButton(text: $name, title: $title)
在Birthday text field
的toolbar
中,将 ScanButton(text:)
替换为以下行:
ScanButton(text: $birthday, title: .constant(title))
您不希望birthday text
影响视图的导航标题。
最后,将 .navigationTitle("Add a Person")
更改为:
.navigationTitle(title)
在您的手机上构建并运行,点击 +
按钮,然后点击Name text field
旁边的Scan Text
按钮。 扫描名称并将其插入。
导航标题更改以匹配插入的名称:
这仅适用于您的Scan Text
按钮。 双击Name text field
,然后使用该扫描按钮,不会更改标题。
还要检查将文本扫描到Birthday text field
不会影响导航标题。
Button Menu
如果您希望Scan Text
选项出现在按钮菜单中,或者您只想让扫描按钮占用更小的空间,请更改创建 ScanButton
的方式。
修改 ScanButton
中的 makeUIView(context:) :
注释掉button
声明并添加以下代码:
let button = UIButton()
button.setImage(
UIImage(systemName: "camera.badge.ellipsis"),
for: .normal)
button.menu = UIMenu(children: [textFromCamera])
您将button
图像设置为一个小的 SF
符号,并将 textFromCamera
操作添加到按钮的菜单中。
在 AddPersonView.swift
中,将 Name text field
的 ScanButton
宽度更改为 56
(或更小):
ScanButton(text: $name, title: $title)
.frame(width: 56, height: 56, alignment: .leading)
在实时预览、模拟器或您的设备上查看这一点。 现在,长按会显示Scan Text
选项。
在本教程中,您练习了在照片中使用实时文本Live Text
,并使用内置的扫描文本功能从手机摄像头获取文本输入。 然后,您指定文本字段的 textContentType
以使 Vision
模型过滤相机输入以获取该格式的文本。
为了让用户更容易看到相机输入功能,您创建了一个 UIViewRepresentable
按钮来启动 captureTextFromCamera(responder:identifier:)
。 对于text fields and text views
,这提供了类似于内置扫描文本按钮的功能。 您可以轻松扩展按钮以将文本扫描到不可编辑的视图中。 最后,您修改了您的按钮,使其具有一个菜单,其中包含扫描文本作为其项目之一。
苹果资源
- WWDC 2021 视频:Use a camera for keyboard input in your app
- 了解响应者链* Understanding the responder chain
- 从相机捕获文本Capture text from camera:在撰写本文时这里没有太多内容,但希望 Apple 会尽快添加更多内容。
后记
本篇主要讲述了基于SwiftUI的文字识别,感兴趣的给个赞或者关注~~~