SwiftUI 中掌握 ScrollView 的使用:滚动可见性

news2024/9/22 23:22:17

在这里插入图片描述

在这里插入图片描述

文章目录

    • 前言
    • 视图修饰符
    • 应用场景
    • 可见性
    • 完整示例
      • ContentView
      • VideoPlayerView
      • ScrollViewVisibilityApp
    • 总结

前言

我们的滚动 API 中又有一个重要的新增功能:滚动可见性。现在,你可以获取可见标识符列表,或者快速检查并监控 ScrollView 内视图的可见性状态。本周,我们将学习如何使用新的 onScrollTargetVisibilityChangeonScrollVisibilityChange 视图修饰符。

视图修饰符

让我们先从 onScrollTargetVisibilityChange 视图修饰符开始。它设计得易于使用,允许你将其附加到具有滚动目标布局的任何 ScrollView 上。让我们通过一个示例来探讨这个修饰符的使用。

struct ContentView: View {
    @State private var visible: [Int] = []
    
    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(1..<100, id: \.self) { item in
                    Text(verbatim: item.formatted())
                }
            }
            .scrollTargetLayout()
        }
        .onScrollTargetVisibilityChange(idType: Int.self) { identifiers in
            visible = identifiers
        }
        .onChange(of: visible) {
            print(visible)
        }
    }
}

如上例所示,我们在懒加载栈(LazyVStack)上使用 scrollTargetLayout 视图修饰符,以便允许 ScrollView 针对栈的子视图进行目标识别,而不是针对栈本身。

要了解有关 scrollTargetLayout 视图修饰符的更多信息,请查看我的文章《掌握 SwiftUI 中的 ScrollView:滚动几何》。

应用场景

我们还将 onScrollTargetVisibilityChange 视图修饰符附加到 ScrollView 上,提供标识符类型和操作闭包。在操作闭包内,我们获取可见标识符列表,并可以对可见项执行所需的操作。

有时,视图需要在其可见性状态在 ScrollView 中发生变化时进行响应。对于这些情况,SwiftUI 框架引入了 onScrollVisibilityChange 视图修饰符,你可以将其附加到 ScrollView 内的任何视图上以处理其可见性。

struct VideoPlayerView: View {
    let url: URL
    
    @State var player: AVPlayer?
    
    var body: some View {
        VideoPlayer(player: player)
            .task {
                if player == nil {
                    player = AVPlayer(url: url)
                }
            }
            .onScrollVisibilityChange { isVisible in
                if isVisible {
                    player?.play()
                } else {
                    player?.pause()
                }
            }
    }
}

上例定义了 VideoPlayerView 视图,该视图在其可见时自动播放视频内容。正如你所见,我们将 onScrollVisibilityChange 视图修饰符附加到视图本身,并提供一个操作闭包。我们在操作闭包内获得可见性参数,并可以对其变化进行响应。

可见性

onScrollVisibilityChangeonScrollTargetVisibilityChange 修饰符都具有 threshold 参数。threshold 参数允许我们调整需要可见的视口部分的数量,以触发操作闭包。默认情况下,SwiftUI 框架使用 0.5 作为阈值,这意味着至少 50% 的视图需要可见,SwiftUI 才会运行操作。但你可以轻松调整此值。

struct VideoPlayerView: View {
    let url: URL
    
    @State var player: AVPlayer?
    
    var body: some View {
        VideoPlayer(player: player)
            .task {
                if player == nil {
                    player = AVPlayer(url: url)
                }
            }
            .onScrollVisibilityChange(threshold: 0.1) { isVisible in
                if isVisible {
                    player?.play()
                } else {
                    player?.pause()
                }
            }
    }
}

在上述示例中,我们定义了阈值,这意味着 SwiftUI 将在视图至少有 10% 可见时运行操作闭包。同样,当视图从可见状态转换为不可见状态,即显示的视口部分少于 10% 时,也会运行该闭包。

完整示例

上面对视图修饰符有了初步了解,它的设计得易于使用,允许你将其附加到具有滚动目标布局的任何 ScrollView 上。让我们通过一个示例来探讨这个修饰符的使用。

示例代码如下:

import SwiftUI
import AVKit

struct ContentView: View {
    @State private var visible: [Int] = []
    
    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(1..<100, id: \.self) { item in
                    Text(verbatim: item.formatted())
                        .frame(width: 100, height: 100)
                        .background(item % 2 == 0 ? Color.blue : Color.red)
                        .cornerRadius(10)
                        .padding(5)
                }
            }
            .scrollTargetLayout()
        }
        .onScrollTargetVisibilityChange(idType: Int.self) { identifiers in
            visible = identifiers
        }
        .onChange(of: visible) { newVisible in
            print("Visible items: \(newVisible)")
        }
        .navigationTitle("ScrollView Demo")
    }
}

struct VideoPlayerView: View {
    let url: URL
    
    @State var player: AVPlayer?
    
    var body: some View {
        VideoPlayer(player: player)
            .frame(height: 200)
            .task {
                if player == nil {
                    player = AVPlayer(url: url)
                }
            }
            .onScrollVisibilityChange { isVisible in
                if isVisible {
                    player?.play()
                } else {
                    player?.pause()
                }
            }
    }
}

@main
struct ScrollViewVisibilityApp: App {
    var body: some Scene {
        WindowGroup {
            NavigationView {
                VStack {
                    ContentView()
                    Spacer()
                    VideoPlayerView(url: URL(string: "https://www.example.com/video.mp4")!)
                        .padding()
                }
            }
        }
    }
}

这个示例 Demo 展示了如何使用 onScrollTargetVisibilityChangeonScrollVisibilityChange 视图修饰符来跟踪 ScrollView 中的视图可见性。整个示例分为两个部分:一个是显示带有多个文本视图的 ScrollView,另一个是显示一个视频播放器视图。

ContentView

  1. ScrollView 和 LazyVStack:使用 ScrollView 包裹一个 LazyVStack,在其中放置 1 到 99 的数字。每个数字都显示在一个 Text 视图中,并有不同的背景颜色。
  2. scrollTargetLayout:在 LazyVStack 上应用 scrollTargetLayout 视图修饰符,以允许 ScrollView 针对栈的子视图进行目标识别。
  3. onScrollTargetVisibilityChange:在 ScrollView 上应用 onScrollTargetVisibilityChange 视图修饰符,并提供标识符类型和操作闭包。在操作闭包内,获取可见标识符列表并赋值给 visible 状态变量。
  4. onChange:监听 visible 状态变量的变化,并打印当前可见的项。

VideoPlayerView

  1. VideoPlayer:定义一个视频播放器视图,使用 AVPlayer 播放视频。
  2. task:在 task 修饰符中初始化播放器。
  3. onScrollVisibilityChange:在视频播放器视图上应用 onScrollVisibilityChange 视图修饰符,并提供一个操作闭包。在操作闭包内,根据可见性状态来播放或暂停视频。

ScrollViewVisibilityApp

  1. 主应用入口:定义主应用入口 ScrollViewVisibilityApp,将 ContentViewVideoPlayerView 组合到一个垂直堆栈中,并通过 NavigationView 进行导航。

运行这个 Demo,你会看到一个带有多个文本视图的 ScrollView,当你滚动时,控制台会打印当前可见的项。此外,在页面底部有一个视频播放器,当视频播放器出现在视口内时,它会自动播放,当其离开视口时,会自动暂停。

总结

今天,我们学习了如何跟踪 ScrollView 内特定视图的可见性,并监控可见标识符列表。示例展示了如何使用 SwiftUI 的滚动可见性修饰符来增强用户体验和交互性。希望能对你有所帮助。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文彻底搞懂 Fine-tuning - 超参数(Hyperparameter)

最近这一两周看到不少互联网公司都已经开始秋招提前批了。不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c;帮助一些球友解…

【Unity】web gl inputFied 中文输入,同时支持TextMeshInputFied,支持全屏

同时支持TextMeshInputFied&#xff0c;支持全屏。 使用github包【WebGLInput】&#xff1a;https://github.com/kou-yeung/WebGLInput 需要资源的在这里也可以下载 https://download.csdn.net/download/weixin_46472622/89600795 用于unity web gl 中文输入&#xff0c;只需…

本地项目提交到Gitee

在项目目录 右键 git bash here 可以在黑屏输入命令 也可以在项目里面 命令都是一样的 要排除哪些 git add . 添加所有文件 git commit -m "Initial commit" 提交到本地 git remote add origin https://gitee.com/xxxx/xxxx.git 添加远程仓库 …

2-54 基于matlab的模糊自适应PID控制器

基于matlab的模糊自适应PID控制器&#xff0c;PID参数的整定必须考虑到在不同时刻三个参数的作用及相互之间的关系。在线实时模糊自整定PID算法的基础上&#xff0c;通过计算当前系统e和误差变化率ec&#xff0c;利用模糊规则进行模糊推理&#xff0c;查询模糊矩阵表进行参数调…

xss漏洞原理及利用【万字详解】

文章目录 url处XSS图片处XSS攻击svg-xss概念复现 pdf-xss概念复现 游览器翻译-xssflash-xss概念常见造成xss中的swf文件函数举例说明&#xff1a; cookie的获取概念代码审计复现 cookie的获取概念代码审计复现 页面信息获取概念条件复现 xss配合MSf钓鱼概念复现 XSS修复对危险字…

47 集合操作与运算

1 增加与删除集合元素 集合对象的 add() 方法可以增加新元素&#xff0c;如果该元素已存在则忽略该操作&#xff0c;不会抛出异常&#xff1b;update() 方法合并另外一个集合中的元素到当前集合中&#xff0c;并自动去除重复元素。 s {1, 2, 3} print(s) s.add(3) # 增加元…

C# 设计模式之装饰器模式

总目录 前言 装饰器模式的主要作用就是扩展一个类的功能&#xff0c;或给一个类添加多个变化的情况。学习面向对象的都知道&#xff0c;如果想单纯的给某个类增加一些功能&#xff0c;可以直接继承该类生成一个子类就可以。应对一些简单的业务场景继承也就够了&#xff0c;但是…

学习笔记-优化问题

目录 一、目前的问题 1、axios 2、跨域问题 3. 路由安全 二、解决问题 1. 跨域问题 2. 优化URL devServer 1. 配置 devServer 2. 修改请求路径 3. 重启 vue 4. 测试 5. pathRewrite 6. 重启 7. 测试 3. 优化 res.data 4. 判断状态码 5. 引入axios 1. 创建自…

【C++】2.C++入门(2)

文章目录 6.引用6.1 引用概念6.2 引用特性6.3 使用场景6.4 const引用&#xff08;常引用&#xff09;6.5 引用和指针的区别 7.inline7.1inline代码举例&#xff1a;7.2inline代码错误示范7.3实现一个ADD宏函数的常见问题&#xff1a; 8.nullptr 6.引用 6.1 引用概念 引用不是…

Yolov8在RK3588上进行自定义目标检测(三)

参考 Yolov8在RK3588上进行自定义目标检测(一) Yolov8在RK3588上进行自定义目标检测(二) best.onnx转yolov8.rknn onnx转rknn需要用到rknn-toolkit2&#xff0c;这个工具暂时不支持windows&#xff0c;所以我们移步linux&#xff0c;我用的是虚拟机创建的ubuntu20.4的系统&a…

JS+H5美观的带搜索的博客文章列表(可搜索多个参数)

实现 美观的界面&#xff08;电脑、手机端界面正常使用&#xff09;多参数搜索&#xff08;文章标题&#xff0c;文章简介&#xff0c;文章发布时间等&#xff09;文章链接跳转 效果图 手机端 电脑端 搜索实现 搜索功能实现解释 定义文章数据: 文章数据保存在一个 JavaScri…

评价指标--深度学习

目录 1分类任务1.1 二分类1.1.1 含义介绍1.1.2 指标 1.2多分类 2图像分割2.1 常用指标2.2 具体含义2.3 代码实现 1分类任务 1.1 二分类 混淆矩阵 1.1.1 含义介绍 TP&#xff1a;预测为真所以是Positive&#xff0c;预测结果和真实结果一致所以为TrueTN&#xff1a;预测为假…

【Python 逆向滑块】(实战六)逆向滑块,并实现用Python+Node.js 生成滑块、识别滑块、验证滑块、发送短信

逆向日期&#xff1a;2024.08.04 使用工具&#xff1a;Python&#xff0c;Node.js 本章知识&#xff1a;逆向【NECaptchaValidate】参数并成功发送短信 文章难度&#xff1a;中等&#xff08;没耐心的请离开&#xff09; 文章全程已做去敏处理&#xff01;&#xff01;&#xf…

【SpringBoot】 定时任务之任务执行和调度及使用指南

【SpringBoot】 定时任务之任务执行和调度及使用指南 Spring框架分别通过TaskExecutor和TaskScheduler接口为任务的异步执行和调度提供了抽象。Spring还提供了支持应用程序服务器环境中的线程池或CommonJ委托的那些接口的实现。最终&#xff0c;在公共接口后面使用这些实现&…

POE服务机器人-快速开始

快速开始 POE与服务机器人部署服务机器人与poe集成迭代你的机器人其他 POE与服务机器人 在本快速入门指南中&#xff0c;我们将使用 Python 构建一个机器人服务器&#xff0c;然后将其与 Poe 集成。一旦您创建了由您的服务器驱动的 Poe 机器人&#xff0c;任何 Poe 用户都可以…

解密XXE漏洞:原理剖析、复现与代码审计实战

在网络安全领域&#xff0c;XML外部实体&#xff08;XXE&#xff09;漏洞因其隐蔽性和危害性而备受关注。随着企业对XML技术的广泛应用&#xff0c;XXE漏洞也逐渐成为攻击者们利用的重点目标。一个看似无害的XML文件&#xff0c;可能成为攻击者入侵系统的利器。因此&#xff0c…

R语言统计分析——描述性统计

参考资料&#xff1a;R语言实战【第2版】 1、整体统计 对于R语言基础安装&#xff0c;可以使用summary()函数来获取描述性统计量。summary()函数提供了最小值、最大值、四分位数、中位数和算术平均数&#xff0c;以及因子向量和逻辑向量的频数统计。 myvars<-c("mpg&…

JRT多维取数据三件套

今天补齐DolerData判断数据是否存在的API&#xff0c;即M的$d。 兜兜转转&#xff0c;经过近十年探索&#xff0c;3年的酝酿&#xff0c;10个月的开发&#xff0c;JRT终于集齐多维取数据三件套。分别是$get,$listget,$data。通过多维取数据的支持&#xff0c;JRT特别适合医疗数…

7.怎么配置一个axios来拦截前后端请求

首先创建一个axios.js文件 导入我们所需要的依赖 import axios from "axios"; import Element from element-ui import router from "./router"; 设置请求头和它的类型和地址 注意先注释这个url,还没有解决跨域问题,不然会出现跨域 // axios.defaults.…

6-5 多输入多输出通道

虽然我们在前面描述了构成每个图像的多个通道和多层卷积层。例如彩色图像具有标准的RGB通道来代表红、绿和蓝。 但是到目前为止&#xff0c;我们仅展示了单个输入和单个输出通道的简化例子。 这使得我们可以将输入、卷积核和输出看作二维张量。 当我们添加通道时&#xff0c;我…