SwiftUI 6.0(iOS 18.0)滚动视图新增的滚动阶段(Scroll Phase)监听功能趣谈

在这里插入图片描述

何曾几时,在 SwiftUI 开发中的秃头小码农们迫切需要一种能够读取当前滚动状态的方法。

在这里插入图片描述

在过去,他们往往需要借助于 UIKit 的神秘力量。不过这一切在 SwiftUI 6.0 中已成“沧海桑田”。

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

  • 1. ScrollView 滚动阶段简介
  • 2. 普度众生的 SwiftUI 6.0
  • 3. 滚动阶段更改上下文(ScrollPhaseChangeContext)
  • 4. 如何监听列表(List)的滚动阶段
  • 总结

相信学完本课后,小伙伴们在需要监听滚动视图滚动阶段的应用场景中定能得心应手、游刃有余!

那还等什么呢?让我们马上开始吧!Let‘s go!!!😃


1. ScrollView 滚动阶段简介

所谓滚动阶段(Scroll Phase)是指滚动视图在滚动前、滚动中以及滚动后所处的不同阶段。

早在 macOS 10.9+ 的 CoreGraphics 中就有滚动阶段的概念了:

在这里插入图片描述
在这里插入图片描述

如果我们能及时的读取各个滚动阶段的值,我们就可以根据它们为滚动视图提供更加“银杏化”的定制和更流畅滚动附加体验。

在 SwiftUI 6.0 之前,我们无法使用行之有效的方法来读取滚动视图当前所处的滚动阶段,只有委身救助于 UIKit 的秉轴持钧。

然而,这一切在 SwiftUI 6.0 中有了翻天覆地的变化!

2. 普度众生的 SwiftUI 6.0

自从 SwiftUI 6.0(iOS 18.0)开始,“顿悟”的苹果终于提供滚动阶段的监听功能了。

一方面,我们有了描述滚动阶段的新类型 ScrollPhase:

在这里插入图片描述

它包含 5 个枚举值分别对应于 5 种滚动阶段:

@frozen public enum ScrollPhase : Equatable {case idlecase trackingcase interactingcase deceleratingcase animatingpublic var isScrolling: Bool { get }
}

这些滚动阶段的含义如下所示:

  • Idle - 表示当前滚动视图处于空闲状态,可以认为“嘛事没有”;
  • Tracking - 表示当前用户正轻触滚动视图但并没有开始滚动;
  • Interacting - 表示用户正在开始或继续滚动着视图的内容;
  • Decelerating -表示用户已结束滚动操作,滚动视图的滚动正在减速直至静止状态;
  • Animating - 表示滚动视图被 ScrollPosition 或 ScrollViewReader 类型通过代码动态滚动到了指定的位置;

另一方面,我们有了新的视图改器方法 onScrollPhaseChange 专注于滚动阶段的监听:

在这里插入图片描述

有了以上两者的珠联璧合,现在我们在 SwiftUI 6.0 即可轻而易举的监听任何滚动视图的滚动阶段啦:

struct ContentView: View {var body: some View {ScrollView {ForEach(1...50, id: \.self) { i inText("Item \(i)").font(.title).padding()Divider()}}.onScrollPhaseChange { old, new inguard old != new else { return }print("new phase: \(new)")}}
}

在 Xcode 16beta 中运行效果如下所示:

在这里插入图片描述

ScrollPhase 类型还提供一个 isScrolling 计算属性,我们可以用它来判断当前是否正在滚动。比如,假若视图正在被滚动我们就“遮挡”它的显示内容:

struct ContentView: View {@State var isScrolling = falsevar body: some View {ScrollView {ForEach(1...50, id: \.self) { i inText("Item \(i)").font(.title).padding()Divider()}.redacted(reason: isScrolling ? .placeholder : [])}.onScrollPhaseChange { old, new inguard old != new else { return }print("正在滚动?\(new.isScrolling)")isScrolling = new.isScrolling}}
}

执行效果如下图所示:

在这里插入图片描述

3. 滚动阶段更改上下文(ScrollPhaseChangeContext)

除此之外,SwiftUI 6.0 中新增的 onScrollPhaseChange 修改器还提供另一种重载(Overloading)形式,在该重载方法的闭包中我们会得到一个 ScrollPhaseChangeContext 上下文对象,使用它我们可以更多的掌控滚动的其它全局信息:

在这里插入图片描述

nonisolated
func onScrollPhaseChange(_ action: @escaping (ScrollPhase, ScrollPhase, ScrollPhaseChangeContext) -> Void) -> some View

演示代码如下所示,可以看到在其中我们使用 ScrollPhaseChangeContext 上下文对象打印出了更多的与滚动相关的信息:

struct ContentView: View {        var body: some View {ScrollView {ForEach(1...50, id: \.self) { i inText("Item \(i)").font(.title).padding()Divider()}        }.onScrollPhaseChange { old, new, context inguard old != new else { return }print("\(new)\n\(context)")            }}
}

运行结果如下所示:

在这里插入图片描述

ScrollPhaseChangeContext(geometry: <ScrollGeometry: contentOffset (0.0, 1694.3333333333333), contentSize (393.0, 4092.0), contentInsets <top: 59.0, leading: 0.0, bottom: 34.0, trailing: 0.0>, containerSize (393.0, 759.0), visibleRect (0.0, 1694.3333333333333, 393.0, 852.0)>, velocity: Optional((0.0, 0.0)))

4. 如何监听列表(List)的滚动阶段

虽然 SwiftUI 6.0 破茧而出的“大杀器” onScrollPhaseChange 对于我们监听滚动状态大有裨益,不过目前它只能应用在 ScrollView 视图的外层。这意味着,如果将其放在 List 上将会“徒劳无功”:

struct ContentView: View {        var body: some View {List {ForEach(1...50, id: \.self) { i inText("Item \(i)").font(.title).padding()}        }.onScrollPhaseChange { old, new, context inguard old != new else { return }print("\(new)\n\(context)")}}
}

上述代码附着在 List 之上的 onScrollPhaseChange 修改器回调闭包将会无所事事,直接沦为“不舞之鹤”。

诚然我们可以使用 ScrollView 来平替 List,不过如果能在 List 上直接监听滚动阶段岂不更妙?

在 iOS 18.0beta 中,我们可以通过将 List 包裹在 Form 容器中暂时绕开此问题:

struct ContentView: View {        var body: some View {Form {List {ForEach(1...50, id: \.self) { i inText("Item \(i)").font(.title).padding()}}}.onScrollPhaseChange { old, new, context inguard old != new else { return }print("\(new)\n\(context)")}}
}

运行代码可以看到,我们用 onScrollPhaseChange 修改器成功的捕获到了 List 中滚动阶段的改变以及其它滚动信息:

在这里插入图片描述

我不确定这一情况在 iOS 18.0 正式版中是否能够修复,让我们拭目以待吧!

总结

在本篇博文中,我们介绍了 SwiftUI 6.0(iOS 18.0)滚动视图最新的滚动阶段(Scroll Phase)监听功能,并讨论了如何在原本不支持该功能的列表(List)上使用它。

感谢观赏,再会啦!😎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/369984.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

植物大战僵尸融合版最新版1.0下载及安装教程

《植物大战僵尸融合版》最新版1.0已经发布&#xff0c;为粉丝们带来了全新的游戏体验。这个版本由B站UP主蓝飘飘fly精心打造&#xff0c;引入了创新的植物融合玩法&#xff0c;让玩家可以享受策略和创意的结合。以下是游戏的详细介绍和安装指南&#xff1a; 游戏特色介绍 全新…

审核平台前端新老仓库迁移

背景 审核平台接入50业务&#xff0c;提供在线审核及离线质检、新人培训等核心能力&#xff0c;同时提供数据报表、资源追踪、知识库等工具。随着平台的飞速发展&#xff0c;越来越多的新业务正在或即将接入审核平台&#xff0c;日均页面浏览量为百万级别。如今审核平台已是公司…

可验证算法在招投标领域的专家“盲抽”中的标段识别码加密应用研究

摘要 在招投标过程中&#xff0c;标段&#xff08;包&#xff09;识别码的安全性至关重要。本文提出了一种基于可验证算法的标段识别码加密方法&#xff0c;以确保其在专家“盲抽”过程中的保密性和可信性。通过对不同表的标段识别码进行全量加密&#xff0c;并通过匹配验证其…

【Nginx】docker运行Nginx及配置

Nginx镜像的获取 直接从Docker Hub拉取Nginx镜像通过Dockerfile构建Nginx镜像后拉取 二者区别 主要区别在于定制化程度和构建过程的控制&#xff1a; 直接拉取Nginx镜像&#xff1a; 简便性&#xff1a;直接使用docker pull nginx命令可以快速拉取官方的Nginx镜像。这个过程…

SpringBoot 启动流程四

SpringBoot启动流程四 前面这个创建对象是初始化SpringApplication对象 是加载了SpringBoot程序的所有相关配置 我们接下来要将这个run方法 run过程是一个运行 初始化容器 我们看我们的运行结果是得到一个ConfigurableApplicationContext对象 package com.bigdata1421.star…

【Android】Android基础--显式Intent和隐式Intent

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

STM32和DHT11使用显示温湿度度(代码理解)+单总线协议

基于STM32CT&#xff0c;利用DHT11采集温湿度数据&#xff0c;在OLED上显示。一定要阅读DHT11数据手册。 1、 DHT11温湿度传感器 引脚说明 1、VDD 供电3.3&#xff5e;5.5V DC 2、DATA 串行数据&#xff0c;单总线 3、NC 空脚 4、GND 接地&#xff0c;电源负极 硬件电路 微…

【Linux进程】进程优先级 Linux 2.6内核进程的调度

前言 进程是资源分配的基本单位, 在OS中存在这很多的进程, 那么就必然存在着资源竞争的问题, 操作系统是如何进行资源分配的? 对于多个进程同时运行, 操作系统又是如何调度达到并发呢? 本文将以Linux kernel 2.6为例 , 向大家介绍进程在操作系统中 (OS) 的调度原理; 1. 进程优…

嵌入式linux面试1

1. linux 1.1. Window系统和Linux系统的区别 linux区分大小写windows在dos&#xff08;磁盘操作系统&#xff09;界面命令下不区分大小写&#xff1b; 1.2. 文件格式区分 windows用扩展名区分文件&#xff1b;如.exe代表执行文件&#xff0c;.txt代表文本文件&#xff0c;.…

.net 调用海康SDK的跨平台解决方案

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,我们面对的不仅仅是技术还有人心,人心不可测,海水不可量,唯有技术,才是深沉黑夜中的一座闪烁的灯塔序言 上2篇海康SDK使用以及常见的坑…

玩转Easysearch语法

Elasticsearch 是一个基于Apache Lucene的开源分布式搜索和分析引擎&#xff0c;广泛应用于全文搜索、结构化搜索、分析等多种场景。 Easysearch 作为Elasticsearch 的国产化替代方案&#xff0c;不仅保持了与原生Elasticsearch 的高度兼容性&#xff0c;还在功能、性能、稳定性…

Python基础小知识问答系列-高效遍历多个不同类型元素的迭代器

1. 问题&#xff1a; 当需要对多个迭代器进行相同遍历操作时&#xff0c;如何避免因为迭代器之间的类型或者迭代器元素 数量过大引发的问题&#xff1f; 2. 解决方法&#xff1a; 使用itertools模块中的chain函数。 示例&#xff1a; from itertools import chainlist_a [2,…

C语言之Const关键字与指针

目录 1 前言2 变量与指针的储存方式3 const int *var;int *const var&#xff1b;const int *const var&#xff1b;理解与区分4 总结 1 前言 实际开发过程中经常遇到const关键字作用于指针的情况&#xff0c;例如&#xff1a;const int *var;int *const var&#xff1b;const…

【前端】从零开始学习编写HTML

目录 一、什么是前端 二、什么是HTML 三、HTML文件的基本结构 四、HTML常见标签 4.1 注释标签 4.2 标题标签 4.3 段落标签 4.4 换行标签 4.5 格式化标签 4.6 图片标签 4.7 超链接标签 4.8 表格标签 4.9 列表标签 4.10 表单标签 &#xff08;1&#xff09;form标…

【vue动态组件】VUE使用component :is 实现在多个组件间来回切换

VUE使用component :is 实现在多个组件间来回切换 component :is 动态父子组件传值 相关代码实现&#xff1a; <component:is"vuecomponent"></component>import componentA from xxx; import componentB from xxx; import componentC from xxx;switch(…

电脑f盘的数据回收站清空了能恢复吗

随着信息技术的飞速发展&#xff0c;电脑已成为我们日常生活和工作中不可或缺的设备。然而&#xff0c;数据的丢失或误删往往会给人们带来极大的困扰。尤其是当F盘的数据在回收站被清空后&#xff0c;许多人会陷入绝望&#xff0c;认为这些数据已无法挽回。但事实真的如此吗&am…

windows server2016搭建AD域服务器

文章目录 一、背景二、搭建AD域服务器步骤三、生成可供java程序使用的keystore文件四、导出某用户的keytab文件五、主机配置hosts文件六、主机确认是否能ping通本人其他相关文章链接 一、背景 亲测可用,之前搜索了很多博客&#xff0c;啥样的都有&#xff0c;就是不介绍报错以…

STM32-I2C硬件外设

本博文建议与我上一篇I2C 通信协议​​​​​​共同理解 合成一套关于I2C软硬件体系 STM32内部集成了硬件I2C收发电路&#xff0c;可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能&#xff0c;减轻CPU的负担 特点&#xff1a; 多主机功能&#x…

利用border绘制三角技巧

绘制三角形的效果如图 <html lang"zh-cn"> <head><meta charset"UTF-8"><title>demo</title><style>* {margin: 0;padding: 0;}.box {/* 盒子宽高改成零就变成三角形 &#xff0c;需要哪个方向的三角形就设置哪个方向…

猫狗图像分类-划分数据集

&#x1f4da;博客主页&#xff1a;knighthood2001 ✨公众号&#xff1a;认知up吧 &#xff08;目前正在带领大家一起提升认知&#xff0c;感兴趣可以来围观一下&#xff09; &#x1f383;知识星球&#xff1a;【认知up吧|成长|副业】介绍 ❤️如遇文章付费&#xff0c;可先看…