SwiftUI:触控反馈
尽管 SwiftUI 并未内置任何触控反馈功能,但对于我们来说,使用 UIKit 和 Core Haptics 进行添加非常容易,这是两个内置于系统中的框架,并且可在所有现代 iPhone 上使用。如果您以前从未听说过“触控反馈”,则“触控反馈”涉及设备中的小型电动机,从而产生诸如敲击和振动之类的感觉。
UIKit 的触控反馈实现非常简单,但这并不意味着您应该排除它:它很简单,因为它专注于内置触控反馈,例如“成功”或“失败”,这意味着用户可以学习感觉如何也就是说,如果您使用成功触控反馈,那么某些用户——尤其是那些更依赖触觉的用户,例如盲人用户——将能够知道操作的结果而无需从您的应用程序获得任何进一步的输出。
要尝试 UIKit 的触控反馈,请将此方法添加到 ContentView
中:
func simpleSuccess() {
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.success)
}
您可以使用一个简单的onTapGesture()
触发它,例如:
Text("Hello, World!")
.onTapGesture(perform: simpleSuccess)
尝试将.success
替换为.error
或.warning
,看看是否可以分辨出其中的区别——我认为,.success
和.warning
相似但不同。
对于更高级的触控反馈,Apple 为我们提供了一个名为 Core Haptics 的整体框架。这东西感觉像是背后的Apple团队的真爱之作,而且我认为它是 iOS 13 中真正的隐藏宝石之一——在看到其说明后我便立即扑向了它!
核心触觉使我们可以通过组合拍子,连续振动,参数曲线等来创建可大规模定制的触觉。我不想在这里过分深入,因为这有点题外话,但我至少想举一个例子,让您自己尝试一下。
首先,在 ContentView.swift 顶部附近添加此新导入:
import CoreHaptics
接下来,我们需要创建一个CHHapticEngine
实例作为属性——这是负责产生振动的实际对象,因此我们需要在需要实现触控反馈效果之前先创建它。
@State private var engine: CHHapticEngine?
我们将在主视图出现后立即创建它。创建引擎时,您可以附加处理程序以帮助停止活动时恢复活动,例如当应用程序移至后台时,但是在这里,我们将使其保持简单:如果当前设备支持触控反馈,我们将启动引擎,如果失败,则打印错误。
将此方法添加到ContentView
:
func prepareHaptics() {
guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return }
do {
self.engine = try CHHapticEngine()
try engine?.start()
} catch {
print("There was an error creating the engine: (error.localizedDescription)")
}
}
现在,有趣的部分是:我们可以配置参数来控制触觉的强度(.hapticIntensity
)和“锐度”的强度(.hapticSharpness
),然后将它们放入具有相对时间偏移的触觉事件中。“锐度”是一个奇怪的术语,但是一旦您尝试过,它就会更有意义——锐度值为0相比于值1确实确实很钝。至于相对时间,这使我们可以创建很多单个序列中的触觉事件。
立即将此方法添加到ContentView
:
func complexSuccess() {
// 确保设备支持触控反馈
guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return }
var events = [CHHapticEvent]()
// 创建一个强烈而尖锐的拍子
let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: 1)
let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: 1)
let event = CHHapticEvent(eventType: .hapticTransient, parameters: [intensity, sharpness], relativeTime: 0)
events.append(event)
// 将这些事件转换为模式并立即播放
do {
let pattern = try CHHapticPattern(events: events, parameters: [])
let player = try engine?.makePlayer(with: pattern)
try player?.start(atTime: 0)
} catch {
print("Failed to play pattern: (error.localizedDescription).")
}
}
要试用我们的自定义触控反馈,请将ContentView
的body
属性修改为此:
Text("Hello, World!")
.onAppear(perform: prepareHaptics)
.onTapGesture(perform: complexSuccess)
这样可以确保触控系统已启动,从而使点击手势正常工作。
如果要进一步尝试触觉,请使用所需的任何触觉替换 let intensity
, let sharpness
, 和 let event
。例如,如果用下面的代码替换这三行,则将获得几次点击,然后依次增加强度和清晰度:
for i in stride(from: 0, to: 1, by: 0.1) {
let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: Float(i))
let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: Float(i))
let event = CHHapticEvent(eventType: .hapticTransient, parameters: [intensity, sharpness], relativeTime: i)
events.append(event)
}
for i in stride(from: 0, to: 1, by: 0.1) {
let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: Float(1 - i))
let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: Float(1 - i))
let event = CHHapticEvent(eventType: .hapticTransient, parameters: [intensity, sharpness], relativeTime: 1 + i)
events.append(event)
}
译自 Making vibrations with UINotificationFeedbackGenerator and Core Haptics
- 温故而知新:HttpApplication,HttpModule,HttpContext及Asp.Net页生命周期
- proxy_pass反向代理配置中url后面加不加/的说明
- Android新手之旅(10) 嵌套布局
- C#代码也VB
- Docker容器学习梳理--SSH方式登陆容器
- Docker网络解决方案-Flannel部署记录
- Nginx的location配置规则梳理
- 统计代码行数的方法梳理
- 如何在不影响asp.net默认安全性的前提下使用ckeditor/fckeditor?
- Linux下防御DDOS攻击的操作梳理
- Android新手之旅(8) ListView的使用
- 更换Ubuntu源为国内源的操作记录
- Android新手之旅(8) ListView的使用
- CKEditor/CKFinder升级心得
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- POJ 1845-Sumdiv(厉害了这个题)
- 数据库SQL语言从入门到精通--Part 1--SQL语言概述
- DP背包(一)
- 程序员最喜欢用的在线代码编译器,什么?你竟然不知道!可以在网页敲代码,运行调试!
- ZOJ 3623 Battle Ships
- POJ 2955 区间DP必看的括号匹配问题,经典例题
- POJ 3211 Washing Clothes
- 1745 Divisibility
- POJ 3616 Milking Time
- C++面向对象编程类对象的定义
- Codeforce 1102 C. Doors Breaking and Repairing
- CodeForces - 1102B Array K-Coloring
- background-size之详解
- a伪类
- CodeForces - 1102A(思维题)