SwiftUI 6.0(iOS 18)自定义容器值(Container Values)让容器布局渐入佳境(上)

在这里插入图片描述

概述

我们在之前多篇博文中已经介绍过 SwiftUI 6.0(iOS 18)新增的自定义容器布局机制。现在,如何利用它们对容器内容进行“探囊取物”和“聚沙成塔”,我们已然胸有成竹了。

在这里插入图片描述

然而,除了上述鬼工雷斧般的新技巧之外,SwiftUI 6.0 其实还提供了能更进一步增加容器布局自由度的新利器:自定义容器值(Container Values)。

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

  • 概述
  • 1. SwiftUI 6.0 中容器内容的遍历
  • 2. SwiftUI 6.0 之前的解决之道
  • 3. 什么是 SwiftUI 6.0 全新的自定义容器值(Container Values)
  • 总结

相信 SwiftUI 6.0 中全新的自定义容器值能够让容器布局更加“脱胎换骨”、灵动自由。

那还等什么呢?让我们马上开始新的容器大冒险吧!Let’s go!!!😉


1. SwiftUI 6.0 中容器内容的遍历

从 SwiftUI 6.0(iOS 18)开始,苹果为 ForEach 和 Group 视图增加了全新的构造器,使它们能够分别实现解析容器单个元素和“鸟瞰”容器整体内容的功能:

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

我们可以将它们看成是 SwiftUI 4.0 中自定义容器布局(Layout)的一个简化版本。

在之前的博客中,我们已经对其做过一些介绍,感兴趣的小伙伴们可以移步如下链接观赏精彩的内容:

  • SwiftUI 6.0(iOS 18)新容器视图修改器漫谈
  • SwiftUI 6.0(iOS 18)将 Sections 也考虑进自定义容器子视图布局(上)
  • SwiftUI 6.0(iOS 18)将 Sections 也考虑进自定义容器子视图布局(下)

下面,请允许我们先写一个非常简单的自定义容器 NiceListContainer 来小试拳脚一番:

struct NiceListContainer<Content: View>: View {@ViewBuilder var content: Contentvar body: some View {List {ForEach(subviews: content) { subview insubview}}}
}

如下代码所示,使用 NiceListContainer 容器很简单:

struct ContentView: View {var body: some View {NiceListContainer {Group {Text("Hello").foregroundStyle(.green)Text("World").foregroundStyle(.red)Text("大熊猫侯佩").foregroundStyle(.brown).font(.system(size: 55, weight: .black))Image(systemName: "globe.europe.africa").resizable().aspectRatio(contentMode: .fit).foregroundStyle(.orange.gradient)HStack {Text("战斗力")Slider(value: .constant(10)).padding()}.tint(.pink)}.font(.title.weight(.heavy))}}
}

我们在上面的演示代码中做了这样几件事:

  • 用 @ViewBuilder 语法将任意子元素放到了 NiceListContainer 容器中;
  • 使用 Group 将这些子元素聚为一组。这不会影响 NiceListContainer 主体中 ForEach(subviews:) 的解析,因为 ForEach 可以将组(Group)中的内容“解开”作为单独的容器元素来遍历;

编译并在 Xcode 预览里可以看到,我们成功的将 NiceListContainer 传入闭包中的每个子视图作为 List 中单个行呈现出来了:

在这里插入图片描述

现在假设我们要实现这样一种功能:在 NiceListContainer 容器中指定子视图的左侧(Leading)加上红色竖线以醒目用户。那么,我们怎么才能让 NiceListContainer 容器知晓哪些子视图需要醒目显示呢?

在下面的代码中,我们假想了这种行为。我们使用臆造的 highlightPrefix() 修改器来向 NiceListContainer 容器表明我们想在这些视图上增加醒目显示的意图:

struct ContentView: View {var body: some View {NiceListContainer {Group {Text("Hello").foregroundStyle(.green).highlightPrefix()Text("World").foregroundStyle(.red).highlightPrefix()Text("大熊猫侯佩").foregroundStyle(.brown).font(.system(size: 55, weight: .black))Image(systemName: "globe.europe.africa").resizable().aspectRatio(contentMode: .fit).foregroundStyle(.orange.gradient)HStack {Text("战斗力")Slider(value: .constant(10)).padding()}.tint(.pink).highlightPrefix()}.font(.title.weight(.heavy))}}
}

那么,我们应该怎样实现上面的 highlightPrefix() 修改器方法呢?大家可以先自己尝试一下。

2. SwiftUI 6.0 之前的解决之道

聪明的小伙伴们可能已经有了一些头绪:我们需要一种方法从容器中的子视图向容器传递消息。这有点像 SwiftUI 中的环境变量,但 @Environment 是从顶向下而不是从底部向上传递消息的。

在 SwiftUI 6.0 之前,我们可以使用 Preference 机制将与子视图绑定的 ID 向上层传递,然后在上层的容器视图中归拢这些 ID,并在这些 ID 对应的视图上应用特殊效果。


关于 Preference 机制的进一步介绍,大家可以到下面的链接中一探究竟:

  • 『番外篇六』SwiftUI 取得任意视图全局位置的三种方法
  • SwiftUI 在 App 中弹出全局消息横幅(下)

关于如何用动态探查技术在运行时获取指定视图的 id 或 tag 值,小伙伴们可以前往如下链接进一步观赏:

  • 『番外篇五』SwiftUI 进阶之如何动态获取任意视图的 tag 和 id 值

另一种办法是,我们可以用 SwiftUI 4.0 Layout 中的自定义布局值来将消息传递给父视图:

在这里插入图片描述

大致的实现如下代码所示:


struct Rotation: LayoutValueKey {static let defaultValue: Binding<Angle>? = nil
}struct ContentView: View {// ...@State var rotations: [Angle] = Array<Angle>(repeating: .zero, count: 16)var body: some View {WheelLayout(radius: radius, rotation: angle) {ForEach(0..<16) { idx inRoundedRectangle(cornerRadius: 8).fill(colors[idx%colors.count].opacity(0.7)).frame(width: 70, height: 70).overlay { Text("\(idx+1)") }.rotationEffect(rotations[idx])// 将自定义的 Rotation 初始值传递到 WheelLayout 中去.layoutValue(key: Rotation.self, value: $rotations[idx])}}// ...
}

在上面代码中,我们使用 layoutValue() 修改器将 Rotation 对应 LayoutValueKey 键的值向上传递给了 WheelLayout 容器。

在 WheelLayout 容器中,我们通过子视图的 LayoutValueKey 键语法糖计算了每个子视图适合的 Rotation 值:

struct WheelLayout: Layout {// ...func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {let angleStep = (Angle.degrees(360).radians / Double(subviews.count))for (index, subview) in subviews.enumerated() {let angle = angleStep * CGFloat(index) + rotation.radians// ...DispatchQueue.main.async {// 计算每个子视图对应的旋转值subview[Rotation.self]?.wrappedValue = .radians(angle)}}}
}

虽然上面这些方法可行,但总觉得有些莫可名状。有没有更简单、更优雅的方法呢?

答案自然是:确定、一定、以及肯定!

3. 什么是 SwiftUI 6.0 全新的自定义容器值(Container Values)

从 SwiftUI 6.0 开始,苹果为定制容器布局新增了自定义容器值(Container Values)的概念。

在这里插入图片描述

简单来说,我们可以使用自定义容器值将所需的状态值附加到容器中指定的子视图上,然后传递到容器的解析和再组合中。

利用 SwiftUI 6.0 中全新的 @Entry 宏,我们还可以进一步简化 Container Values 的定义。

在这里插入图片描述


细心的小伙伴们可能发现了,在上图中的 Entry 宏貌似从 iOS 13(SwiftUI 1.0)就开始支持了,如果不是苹果“犯浑”的话,原因可能是苹果决定把这个特性大幅度向前兼容吧。

更多 @Entry 宏的介绍,请小伙伴们移步如下链接观赏进一步的内容:

  • SwiftUI 6.0(Xcode 16)全新 @Entry 和 @Previewable 宏让开发妙趣横生

在下一篇博文中,我们就来看看如何在 SwiftUI 6.0 中优雅的使用 Container Values 吧。

总结

在本篇博文中,我们介绍了如何用 SwiftUi 6.0 全新的自定义容器机制解析容器子元素,并初步介绍了何为 SwiftUI 6.0 全新的自定义容器值(Container Values)。

感谢观赏,再会啦!😎

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

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

相关文章

10月15日 -- 11月15日 ,参与《人工智能导论》学习打卡赢B站大会员

一、活动参与地址 点击链接进行活动报名>>>https://momodel.cn/classroom/course/detail?id6173911eab37f12b14daf4a8&activeKeyinfo&srcbef3adb478 二、活动详情 进入链接点击报名&#xff0c;仅需每天参与吴超老师的《人工智能导论》打卡活动&#xff0…

NPCAP和WPCAP

NPCAP是专为Windows开发的一款网络抓包SDK,该SDK提供了被应用程序调用的库文件和系统驱动程序。通过Npcap,我们可以得到原始网络数据,即未经过TCP/IP协议栈的数据,也就是网卡收到的数据,同时呢,我们也可以通过NPCAP设置接收过滤器,这样收到的数据就是我们感兴趣的数据,…

[C++ 核心编程]笔记 4.1.4 类和对象 - 案例1

类和对象: 案例1: 设计立方体类(Cube) 求出立方体的面积和体积分别用全局函数和成员函数判断两个立方体是否相等。 设计方法: 创建立方体类设计属性设计行为 求立方体面积和体积分别用全局和成员函数 判断立方体是否相等 #include<iostream> using namespace std;clas…

正则表达式-“三剑客”(grep、sed、awk)

1.3正则表达式 正则表达式描述了一种字符串匹配的模式&#xff0c;可以用来检查一个串是否含有某种子串&#xff0c;将匹配的子串替换或者从某个串中取出符号某个条件的子串等&#xff0c;在linux中代表自定义的模式模版&#xff0c;linux工具可以用正则表达式过滤文本。Linux…

★ C++进阶篇 ★ AVL树实现

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将继续和大家一起学习C进阶篇第五章----AVL树实现 ~ ❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️澄岚主页&#xff1a;椎名澄嵐-CSDN博客C专栏&#xff1a;★ C进阶篇 ★_椎名澄嵐的博客-CSDN博客 ❄️…

Java基础:面向对象编程3

1 Java可变长参数 1.1 概述 Java 的可变长参数&#xff08;Varargs&#xff09;是在 Java 1.5 中引入的功能&#xff0c;允许方法接受任意数量的相同类型的参数。可变参数的语法是在参数类型后面加上三个点&#xff08;...&#xff09;&#xff0c;例如 int... numbers。 1.…

IPV6学习汇总

一、ICMPV6 ICMPv6&#xff08;Internet Control Message Protocol version 6&#xff09;&#xff0c;即互联网控制信息协议版本六&#xff0c;是为了与IPv6配套使用而开发的互联网控制信息协议。以下是关于ICMPv6的详细介绍&#xff1a; 一、基本功能 ICMPv6向源节点报告关…

半小时速通RHCSA

1-7章: #01创建以上目录和文件结构&#xff0c;并将/yasuo目录拷贝4份到/目录下 #02查看系统合法shell #03查看系统发行版版本 #04查看系统内核版本 #05临时修改主机名 #06查看系统指令的查找路径 #07查看passwd指令的执行路径 #08为/yasuo/ssh_config文件在/mulu目录下创建软链…

Vulnhub:DarkHole_2

一.信息收集/站点收集 &#xff08;1&#xff09;根据物理地址用nmap的主机发现功能得出IP地址 nmap -P 192.168.138.0/24 //同网段下主机发现得到IP为192.168.138.185&#xff08;2&#xff09;做nmap的目录扫描和端口扫描来发现其他站带以及信息 nmap -p- 192.168.138.185 …

什么是DApp?DApp开发指南

一、什么是DApp&#xff1f; DApp&#xff08;Decentralized Application&#xff09;&#xff0c;即去中心化应用&#xff0c;是一种基于区块链技术开发的应用程序&#xff0c;与传统的中心化应用不同&#xff0c;DApp不依赖单一服务器或管理主体&#xff0c;而是利用去中心化…

Oracle数据库安装Windows版本

1.下载压缩包 首先下载oracle19c的数据库&#xff0c;可以在官网下载&#xff0c;也可以从我的百度网盘下载。文件比较大&#xff0c;从oracle官网&#xff08;外网&#xff09;下载速度比较慢&#xff0c;还需要注册oracle用户。 通过网盘分享的文件&#xff1a;oracle数据库…

路由器概述

一、路由器的工作原理 根据路由表转发数据 二、路由表与其形成 2.1路由表 &#xff08;1&#xff09;概念 路由&#xff1a;从源主机到目的主机的转发过程路由表&#xff1a;路由器中维护的路由条目的集合&#xff1b;路由器根据路由表做路径选择 &#xff08;2&#xff…

k8s、prometheus、grafana数据采集和展示的链路流程

k8s集群中&#xff0c;容器级别的数据采集是由cAdvisor程序实现 cAdvisor # Container Advisor 容器顾问 cAdvisor程序是kubelet组件的一部分。 每个节点&#xff0c;包括master节点&#xff0c;都有一个kubelet系统服务&#xff0c; kukelet负责管理pod和容…

多台服务器分布式定时调度的几种方案

背景&#xff1a;现在有多个后端服务器&#xff0c;并且在代码中定义了一个定时任务&#xff0c;希望这个定时任务在一个时间只在一个服务器上执行&#xff0c;涉及到分布式调度&#xff0c;调研了一下总结出几种方案&#xff1a; 1.mysql的内置GET_LOCK GET_LOCK方法的介绍 …

TCP/IP相关

1、关于三次握手、四次挥手和TCP的11种状态&#xff1a; 记住这张图就行了&#xff1a; 2、关于慢启动、拥塞避免、超时重传、快速重传、快速恢复 记住这张图就行了&#xff1a; 一些名词解释&#xff1a; MSS&#xff1a;Maximum Segment Size&#xff0c;最大报文长度 RT…

[论文阅读]SCOTT: Self-Consistent Chain-of-Thought Distillation

中文译名&#xff1a;SCOTT: 思维链一致性蒸馏 会议&#xff1a;Proceedings of the 61st Annual Meeting of the Association for Computational Linguistics (Volume 1: Long Papers) 链接&#xff1a;SCOTT: Self-Consistent Chain-of-Thought Distillation - ACL Antholo…

简单概述Ton链开发路径

区块链开发领域发展迅速&#xff0c;各种平台为开发人员提供不同的生态系统。其中一个更有趣且越来越相关的区块链是TON&#xff08;开放网络&#xff09;区块链。TON 区块链最初由 Telegram 构思&#xff0c;旨在提供快速、安全且可扩展的去中心化应用程序 (dApp)。凭借其独特…

CSS简单入门

一.简单概念 1.概念 层叠样式表&#xff0c;一种样式表语言&#xff0c;用来美化HTML文档的呈现。 2.书写位置 title标签下方添加style双标签&#xff0c;style标签里面书写CSS代码 &#xff08;1&#xff09;外部学习样式 <title>CSS使用</title> <sty…

【2022统考真题】计算时间复杂度

目录 一、题目描述 二、思路分析 三、易错提醒 四、同级和嵌套的关系 一、题目描述 下列程序段的时间复杂度是&#xff08;&#xff09; int sum 0; for (int i 1; i < n; i * 2) for (int j 0; j < i; j) sum; A. O(logn) B. O(n) C. O(nlogn) D…

前端转换double数据,保留两位小数

Number Number(1.00) 1 Number(1.10) 1.1 Number(1.101) 1.101 要想前端展示页面按 1.00展示1&#xff0c;1.10 展示1.1 需要套一个number() 1.1 保留两位小数&#xff0c;并三位一个分隔符 indexView.value[key] formatNumber(indexView.value[key].toFixed(2))//格式…