SwiftUI 5.0(iOS 17.0)触摸反馈“震荡波”与触发器模式趣谈

embedded/2024/9/25 10:39:00/

在这里插入图片描述

概览

要想创作出一款精彩绝伦的 App,绚丽的界面和灵动的动画并不是唯一吸引用户的要素。有时我们还希望让用户真切的感受到操作引发的触觉反馈,直击使用者的灵魂。

在这里插入图片描述

所幸的是新版 SwiftUI 原生提供了实现触觉震动反馈的机制。在介绍它之后我们还将进一步展开讨论该机制基于的触发器模式,并“青出于蓝而胜于绿”的设计我们自己的触发器实现。

在本篇博文中,您将学到如下内容:

相信学完本课后,小伙伴们对于 SwiftUI 中触觉反馈与触发器开发模式会有更深刻的领悟,从而能够更加游刃有余的使用它们。

那还等什么呢?We will rock you!!!😉


1. “震荡波”来袭

除了从视觉上强势吸引用户眼球之外,我们的 App 还可以用“更立体”的方式让用户爱不释手。是滴,我们就是要用触觉反馈震动他们“久逢甘露”的双手,用“震荡波”激荡他们的心灵。

震动反馈Haptic )是 Apple 对于移动设备提供的一种加强用户体验的机制,它最早诞生于 UIKit。它的体验有点类似于之前 iPhone 中 3D Touch 的功能。

Haptic 被广泛应用在 iOS/iPadOS 中,Apple 系统在用户交互中大量使用了震动反馈,比如在锁屏状态下点击 iPhone 屏幕左下角的手电筒按钮:

在这里插入图片描述

或者 iPhone 隔空投送完成时给于用户的提示反馈,以及 AppleWatch 上的通知提醒等等。

更多 Haptic 撸码的相关介绍,请小伙伴们移步 Apple 官方开发网站观赏进一步内容:

  • Playing a single-tap haptic pattern

在这里插入图片描述

在这里插入图片描述

前面说过 Haptic 最先是在 UIKit 中得到很好支持的,从 SwiftUI 5.0iOS 17.0)开始苹果终于推出了 SwiftUI 里 Haptic 的原生实现 SensoryFeedback

在这里插入图片描述

如上所示,SensoryFeedback 结构的“借花献佛”是通过视图扩展方法 sensoryFeedback 来完成的:

@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
@available(visionOS, unavailable)
extension View {/// - Parameters:///   - feedback: Which type of feedback to play.///   - trigger: A value to monitor for changes to determine when to play.public func sensoryFeedback<T>(_ feedback: SensoryFeedback, trigger: T) -> some View where T : Equatable/// - Parameters:///   - feedback: Which type of feedback to play.///   - trigger: A value to monitor for changes to determine when to play.///   - condition: A closure to determine whether to play the feedback when///     `trigger` changes.public func sensoryFeedback<T>(_ feedback: SensoryFeedback, trigger: T, condition: @escaping (_ oldValue: T, _ newValue: T) -> Bool) -> some View where T : Equatable/// - Parameters:///   - trigger: A value to monitor for changes to determine when to play.///   - feedback: A closure to determine whether to play the feedback and///     what type of feedback to play when `trigger` changes.public func sensoryFeedback<T>(trigger: T, _ feedback: @escaping (_ oldValue: T, _ newValue: T) -> SensoryFeedback?) -> some View where T : Equatable}

可以看到 sensoryFeedback 方法拥有多个重写形式,但它们都毫无例外的使用了触发器模式(Trigger Mode)。

2. 触发器模式

什么是触发器模式呢?在 Apple 的开发中大家可能对观察者模式早就有所耳闻,触发器模式与此类似也属于苹果开发中的一种设计模式。触发器模式就是让状态的改变触发代码的执行。

在以状态驱动的 SwiftUI 王国中,触发器模式的使用更显得“如鱼得水”,仿佛天造地设一般。

struct ContentView: View {@State private var store = Store()var body: some View {NavigationStack {List(store.results, id: \.self) { result inText(result.title)}.searchable(text: $store.query).sensoryFeedback(.success, trigger: store.results)}}
}

在上面的示例代码中,我们使用 sensoryFeedback 修改器方法为视图添加了震动反馈。其中可以看到:Haptic 产生的触发器是 store.results 状态,即当用户引起 Store 搜索结果发生改变时,我们纤细指尖才会喜提激荡震动着的触觉洗礼。

除了感受系统内置震动效果对“心灵的冲击”以外,我们还可以让震动更加“变幻莫测”:

VStack {}
.sensoryFeedback(.impact(weight: .heavy, intensity: 0.9),trigger: trigger
)

类似的,大家还可以根据状态实际的值来决定到底使用何种 Haptic 效果,比如在下面的代码中我们就根据搜索是否成功来决定采用 .error 还是 .success 震动反馈类型:

List(store.results, id: \.self) { result inText(result)}.searchable(text: $store.query).sensoryFeedback(trigger: store.results) { oldValue, newValue inreturn newValue.isEmpty ? .error : .success}

注意,上面所有 Haptic 效果只有在触发器对应状态发生改变时才会产生,所以我们不用担心视图创建时触发器导致不希望的“副作用”。

3. SwiftUI 触发器模式的其它应用

除了 Haptic 对应的实现以外,在 SwiftUI 中还有很多其它功能也大量适配触发器模式。比如 scrollIndicatorsFlash 修改器方法:

在这里插入图片描述

scrollIndicatorsFlash 方法用来在指定状态发生改变时来“闪烁”可滚动视图中的滚动条:

struct TriggerValueExample: View {let messages: [String]var body: some View {List(messages, id: \.self) { message inText(verbatim: message)}.scrollIndicatorsFlash(trigger: messages)}
}

在上面的代码中,当有新消息到来时我们会“闪烁”列表的滚动条以提示用户。

4. 自定义触发器模式

通过上面的介绍,想必大家对于何为触发器模式以及它的工作原理已经了然于心了。触发器模式在 SwiftUI 中被广泛地使用着,那我们能不能“百尺竿头更进一步”打造自己的触发器呢?

答案是肯定的!

正如观察者模式那样,设计模式意味着提供充分可定制的灵活性,除了使用系统框架提供的触发器以外,我们当然可以随心所欲地创建自己的触发器

假如我们希望在 SwiftUI 中当某一状态发生改变时播放指定的声音,这可以恰如其分的用触发器模式来实现:

struct PlaySoundViewModifier<Trigger: Equatable>: ViewModifier {let sound: URLlet trigger: Triggerfunc body(content: Content) -> some View {content.onChange(of: trigger) {if let player = try? AVAudioPlayer(contentsOf: sound) {player.play()}}}
}extension View {func playSound(_ sound: URL, trigger: some Equatable) -> some View {self.modifier(PlaySoundViewModifier(sound: sound, trigger: trigger))}
}

在上面的示例代码中,我们创建了 PlaySoundViewModifier 修改器方法,并绑定了一个遵守 Equatable 协议,类型为 Trigger 的属性,当 trigger 发生变化时,我们就利用 AVAudioPlayer 对象从容地播放想要的声音文件。

小伙伴们可以这样使用上面创建的 PlaySoundViewModifier 修改器方法:

struct SoundFeedbackExample: View {let messages: [String]var body: some View {List(messages, id: \.self) { message inText(verbatim: message)}.playSound(Bundle.main.url(forResource: "sound", withExtension: "wav")!,trigger: messages)}
}

看到了吗?触发器模式就是这么单刀直入,让代码实现变得如此直接了当。从此小伙伴们开发兵器库中又多了一件神兵利器,棒棒哒!💯


想要系统学习 Swift 语言的小伙伴们,千万不要错过我的《Swift 语言开发精讲》专栏哦:

在这里插入图片描述

  • Swift 语言开发精讲

总结

在本篇博文中,我们介绍了 SwiftUI 5.0iOS 17.0)中触觉反馈(Haptic)机制的实现,并由此抛砖引玉讨论了开发模式中的触发器模式,最后我们看到了实现自己心仪的触发器是多么的简单。

感谢观赏,再会!😎


http://www.ppmy.cn/embedded/11165.html

相关文章

fnm:Rust开发的高效Node版本管理工具

简介 fnm 是一个基于 Rust 开发的 Node 版本管理工具&#xff0c;它的目标是提供一个快速、简单且可靠的方式来管理 Node.js 的不同版本。同时&#xff0c;它是跨平台的&#xff0c;支持 macOS、Linux、Windows。&#x1f680; Fast and simple Node.js version manager, buil…

notepad++快捷键和宏录制

想要一个删除行的快捷键, 发现没有 有个现成的快捷键 CtrlL : 剪切当前行 , 不是我想要的效果 宏录制很方便,于是就录制一个删除行的宏,设置快捷键为: CtrlD 录制宏: 1, 点击"开始录制" 2, 依次按键: End , Space , Shift Home , Delete , Delete 3, 点击"停止…

的记忆:pandas(实在会忘记,就看作是一个 Excel 表格,或者是 SQL 表,或者是字典的字典。)

pandas 是一个开源的 Python 数据分析库&#xff0c;它提供了快速、灵活和富有表现力的数据结构&#xff0c;旨在使“关系”或“标记”数据的“快速分析、清洗和转换”变得既简单又直观。pandas 非常适合于数据清洗和转换、数据分析和建模等任务。以下是 pandas 的基本概念和主…

算法打卡day50|单调栈篇01| Leetcode 739. 每日温度、496.下一个更大元素 I

算法题 Leetcode 739. 每日温度 题目链接:739. 每日温度 大佬视频讲解&#xff1a;739. 每日温度视频讲解 个人思路 因为题目所求的是找到一个元素右边第一个比自己大的元素&#xff0c;这是单调栈的经典题目&#xff0c;用栈来记录遍历过的元素 解法 单调栈 单调栈的本质…

大数据第五天(操作hive的方式)

文章目录 操作hive的方式hive 存储位置hive 操作语法创建数据表的方式 操作hive的方式 hive 存储位置 hive 操作语法 创建数据表的方式 – 创建数据库 create database if not exists test我们创建数据库表的时候&#xff0c;hive是将我们的数据自动添加到数据表中&#xf…

物理安全中-机房安全包含哪些内容

机房安全在物理安全中的核心要素及其重要性 在信息化社会中,机房作为承载关键信息基础设施的核心区域,其物理安全的构建与维护具有至关重要的意义。确保机房的安全性、稳定性和持续运行能力,是有效保护数据资源、维持业务正常运行的基础。本文将详述机房安全所涵盖的主要内…

ubuntu22.04搭建dns内网

近期&#xff0c;需要在无网络的ubuntu环境下搭建内部可用的dns内网&#xff0c;总共花费3个工作日晚上&#xff0c;总算成功搭建&#xff0c;做个记录&#xff0c;记录踩坑记录&#xff0c;同时方便以后翻阅。 安装软件包&#xff1a; 有网络环境下&#xff0c;比较简单&…

公钥和公有地址有什么区别?

目录 前言&#xff08;为了回答这个问题&#xff0c;有几件事需要理解。&#xff09; 1、首先是哈希是什么。 2、接下来要了解的是公钥和私钥 3、其他 公钥和公有地址有什么区别&#xff1f; 总结 前言&#xff08;为了回答这个问题&#xff0c;有几件事需要理解。&#…