SwiftUI 6.0(iOS 18)新容器视图修改器漫谈

news/2024/7/14 22:38:34

在这里插入图片描述

概览

本届 WWDC 2024 观影正如火如荼的进行中,一片鸟语花香、枝繁叶茂的苹果树上不时结出几颗令人垂涎欲滴的美味苹果让秃头码农们欲罢不能。

在这里插入图片描述

如您所愿,在界面布局“利器” SwiftUI 这根蔓藤也长出不少喜人的果实,其中在 iOS 18.0 中新添加的容器视图修改器大家一定不能错过。

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

  • 概览
  • 1. 探囊取物:获取容器子视图
  • 2. 聚沙成塔:重新组织容器子视图
  • 总结

SwiftUI 6.0 新容器视图修改器让我们得以分解原本“铁板一块”的“黑箱”视图,打开无限可能。

无需等待,让我们马上开始探寻之旅吧!

Let’s go!!!😉


本文对应的视频课在此,欢迎小伙伴们恣意观赏

SwiftUI 6.0(iOS 18)新容器视图修改器漫谈


1. 探囊取物:获取容器子视图

在 SwiftUI 6.0(iOS 18)之前,如果我们希望让自定义容器视图处理布局排版的细节则需要知道数据集,并根据数据集中每个单独元素构建对应的容器子视图:

import SwiftUIstruct MyContainerView<Content: View>: View {var items: [Int]@ViewBuilder var itemView: (Int) -> Contentvar body: some View {List {ForEach(items, id: \.self) { item initemView(item)}}}
}struct ContentView: View {var body: some View {MyContainerView(items: Array(1...10)) { item inText("Item \(item)").font(.title).padding()}}
}

如上代码所示,我们将容器数据集合 items 和单个数据对应的子视图闭包 itemView() 从父视图传入到了 MyContainerView 中。

在这里插入图片描述

不过在某些情况下,我们希望在父视图中更灵活的创建容器子视图,比如以静态与动态相结合的方式:

struct ContentView: View {var body: some View {MyContainerView {Text("Item Header")Text("Item Subheader")ForEach(1...10, id: \.self) { item inText("Item \(item)")}Text("Item Tail")}}
}

如上代码所示,我们试图将 3 个静态和 10 个动态产生的子视图和睦融洽的一起融入到容器视图 MyContainerView 中。但不幸的是,这在 SwiftUI 6.0 之前几乎是不可能完成的任务。


当然,如果我们巧妙运用一些 Swift Mirror “黑魔法”的话也不是绝对不可能。想要进一步了解 Mirror 黑魔法解决之道的小伙伴们,请移步如下链接观赏精彩的内容:

  • SwiftUI 打造一款收缩自如的 HStack(三):“魔镜魔镜,我爱你”

究其原因则是因为:在 SwiftUI 6.0 之前我们无法探查一个 View 的内部结构,它对我们来说就是一个彻头彻尾的“黑盒”视图。

不过从 SwiftUI 6.0(iOS 18)开始情况有了改观,苹果新增了若干容器视图修改器为我们排愁解忧。其中 ForEach(subviewOf:) 修改器方法就是这里我们所需要的那个“救世主”。

在这里插入图片描述

利用 ForEach(subviewOf:) 方法我们可以将 MyContainerView 容器视图修改为如下模样:

struct MyContainerView<Content: View>: View {@ViewBuilder var content: Contentvar body: some View {List {ForEach(subviewOf: content) {subview insubview.padding().frame(maxWidth: .infinity).background(.green.gradient)}}}
}

从上面修改后的代码中可以看到:现在我们只需专注于子视图本身,而无需再操心对应的子元素 Item 了。

在这里插入图片描述

除了 ForEach(subviewOf:) 以外,SwiftUI 6.0 还新增了一个类似的 ForEach(sectionOf: ) 修改器方法,如果小伙伴们希望自己的容器支持 Section 布局则会寻求它的鼎力相助哦。

2. 聚沙成塔:重新组织容器子视图

在聊完了将一整块黑盒视图从布局上分解为各个独立的子视图后,我们再来看看容器视图的另一种操作:将容器子视图重新“恣意”组合在一起。

假如我们希望自己的容器视图能够进一步根据子视图的数量或其它特定条件来布局界面,那么新的 Group(subviewsOf:) 修改器你绝对不能错过:

在这里插入图片描述

Group(subviewsOf: content) 方法让我们可以从整个容器的所有子视图而不是单个子视图来考虑布局大计:

struct HyListView<Content: View>: View {@ViewBuilder var content: Contentvar body: some View {VStack {Group(subviewsOf: content) { subviews inif subviews.isEmpty {Text("🐼No\nContent").font(.system(size: 100)).padding()} else {if let first = subviews.first {first.font(.largeTitle.weight(.heavy)).background(Circle().foregroundStyle(.blue.gradient).frame(width: 150, height: 150))}if subviews.count >= 3 {HStack {subviews[1]subviews[2]}.font(.title).foregroundStyle(.white).padding().background(.green)if subviews.count > 3 {List {subviews[3...].frame(maxWidth: .infinity).padding().background(.yellow.gradient)}.listStyle(.plain).font(.title3.weight(.black)).foregroundStyle(.red).padding()}}}}.transition(.slide)}}
}struct ContentView: View {@State var count = 10.0var items: [Int] {if count == 0 {[]} else {Array(0...Int(count))}}var body: some View {VStack {HyListView {ForEach(items, id: \.self) { i inText("Item \(i)")}}.animation(.bouncy, value: count)Spacer()HStack {Text("\(Int(count))").fontWeight(.heavy)Slider(value: $count, in: 0...20.0, label: {}, minimumValueLabel: {Text("0")}, maximumValueLabel: {Text("20")}).foregroundStyle(.gray)}.padding()}}
}

在上面代码中,我们创建了自己的 HyListView 容器视图,并且根据实际子视图的数量利用 Group(subviewsOf: content) 修改器方法来决定到底如何将它们“浑然天成”的组合在一起。

在这里插入图片描述

从实际运行效果可以看到,我们动态的根据容器内部的子视图来决定到底如何布局容器本身,再辅以动画整个效果简直 Nice 的不要不要的:

在这里插入图片描述

现在小伙伴们手握 SwiftUI 6.0 中新的容器视图修改“利器”,在 App 的开发中是不是愈发感觉神采奕奕、容光焕发了呢?棒棒哒!

总结

在本篇博文中,我们讨论了 WWDC24 里 SwiftUI 6.0(iOS 18)中最新的容器视图修改器,并用简单的示例代码让小伙伴们豁然开朗!

感谢观赏,再会!😎


http://www.mrgr.cn/p/34764577

相关文章

Dorkish:一款针对OSINT和网络侦查任务的Chrome扩展

关于Dorkish Dorkish是一款功能强大的Chrome扩展工具&#xff0c;该工具可以为广大研究人员在执行OSINT和网络侦查任务期间提供强大帮助。 一般来说&#xff0c;广大研究人员在执行网络侦查或进行OSINT信息收集任务过程中&#xff0c;通常会使用到Google Dorking和Shodan&…

迅狐跨境商城系统|全平台兼容|前端采用uni-app跨端框架,后端采用ThinkPHP5框架

高效实现全平台兼容的迅狐跨境商城系统 迅狐跨境商城系统是一款专为跨境电商企业设计的全平台兼容系统。其前端采用uni-app跨端框架&#xff0c;后端采用ThinkPHP5框架&#xff0c;旨在实现高效的开发和运营管理。 1. 全平台兼容的前端设计 迅狐跨境商城系统的前端采用uni-a…

Spring运维之boo项目表现层测试加载测试的专用配置属性以及在JUnit中启动web服务器发送虚拟请求

测试表现层的代码如何测试 加载测试的专用属性 首先写一个测试 假定我们进行测试的时候要加一些属性 要去修改一些属性 我们可以写一个只在本测试有效的测试 写在配置里 测试 打印输出 我们把配置文件里面的配置注释掉后 我们同样可以启动 package com.example.demo;impo…

12 款 Android 照片恢复应用程序列表

丢失难忘的照片总是令人痛苦的。如果软件崩溃或意外删除&#xff0c;Android 设备上的照片也可能会丢失。这时照片恢复应用程序就派上用场了。查看我们为 Android 收集的顶级照片恢复应用程序。 但是&#xff0c;您不会想为自己选择任何照片恢复应用程序。因此&#xff0c;我们…

STM32CubeMX配置-RTC周期唤醒

一、简介 MCU为STM32G070&#xff0c;采用内部时钟32KHZ&#xff0c;配置为周期6s唤醒&#xff0c;调用回调函数&#xff0c;进行喂狗操作。 二、配置 初始时间、日期、周期唤醒时间配置。 开启周期唤醒中断 三、生成代码 调用回调函数&#xff0c;进行喂狗操作。 //RTC唤醒回…

环形链表2证明

解法 快慢指针相遇后&#xff0c;其中一个指回头部&#xff0c;然后同步前进 代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:ListNod…

爱心代码来喽

今天给大家分享一个爱心代码&#xff0c;送给我的粉丝们。愿你们天天开心&#xff0c;事事顺利&#xff0c;学业和事业有成。 下面是运行代码&#xff1a; #include<stdio.h> #include<Windows.h> int main() { system(" color 0c"); printf(&q…

图解 Twitter 架构图

写在前面 两年前&#xff0c;马老板收购了twitter&#xff0c;并且做了一系列的大动作。那么今天我们来看一下这个全球最火的软件之一的架构。 Twitter解析 开始之前&#xff0c;我先提前说明一下&#xff0c;我之前不是做搜推广的&#xff0c;所以对这些了解不是很深&…

LabVIEW常用的加密硬件

LabVIEW在工程和科学领域中广泛应用&#xff0c;其中数据保护和程序安全尤为重要。为了确保数据的安全性和完整性&#xff0c;常用的加密硬件设备包括TPM&#xff08;可信平台模块&#xff09;、HSM&#xff08;硬件安全模块&#xff09;和专用加密芯片。本文将推荐几款常用的加…

Excel自定义排序和求和

概览 excel作为办公的常备工具&#xff0c;好记性不如烂笔头&#xff0c;在此梳理记录下&#xff0c;此篇文章主要是记录excel的自定义排序和求和 一. 自定义排序 举个例子 1. 填充自定义排序选项 实现步骤&#xff1a; 选定目标排序值&#xff1b;文件->选项->自定…

如何交叉编译Libsndfile

Libsndfile 是一个用于读取和写入文件的 C 库&#xff0c;它支持多种音频文件格式&#xff0c;包括 WAV、AIFF、FLAC 等。这个库提供了一个简单的 API 来处理音频数据&#xff0c;使得开发者可以在他们的应用程序中轻松地集成音频文件的读写功能。今天介绍一下如何针对x210平台…

多种方案图文并茂分分钟教你解决Kubernetes(k8s)容器安全问题(不断更新中)

Kubernetes(k8s)Secrets in clear text environment variables 明文中的秘密环境变量 问题详解在Kubernetes(k8s)中,Secrets用于管理诸如密码、令牌和密钥等敏感信息。安全地存储这些密钥至关重要。然而,将密钥直接注入到明文环境变量中可能会使它们面临潜在的安全风险。…

机器,学习没有捷径

1 捷径学习 1.1 你捷径学习了么 深度学习因为其优异的学习能力&#xff0c;已经成为推动人工智能发展当之无愧的主力军。深度学习在NLP和CV等不同的场景下都展现了优异的能力。但深度学习也存在一个与生俱来的问题&#xff1a;捷径学习。 捷径学习中的捷径表示的是一种有缺陷…

定个小目标之刷LeetCode热题(21)

这是道技巧题&#xff0c;利用了 &#xff08;num - 1&#xff09;% n 计算下标的形式来将数组元素与数组索引产生映射关系&#xff0c;代码如下&#xff0c;可以看下注释 class Solution {public List<Integer> findDisappearedNumbers(int[] nums) {int n nums.lengt…

异或运算在面试题中的应用

异或运算 是 涉及到数据位运算时常见的处理方式。如何进行异或运算?在对应位上,相同为0,不同1,但其实两个数据异或运算就是进行无进位加法。 例如: int a = 7, b = 6, a ^b = ? 算法1: 相同为0,不同为1 a ^ b= : 0 0 0 1 算法2: 无进位…

Web端在线/离线Stomp服务测试与WebSocket服务测试

Stomp服务测试 支持连接、发送、订阅、接收&#xff0c;可设置请求头、自动重连 低配置云服务器&#xff0c;首次加载速度较慢&#xff0c;请耐心等候 预览页面&#xff1a;http://www.daelui.com/#/tigerlair/saas/preview/lxbho9lkzvgc 演练页面&#xff1a;http://www.da…

Pyshark——安装、解析pcap文件

1、简介 PyShark是一个用于网络数据包捕获和分析的Python库&#xff0c;基于著名的网络协议分析工具Wireshark和其背后的libpcap/tshark库。它提供了一种便捷的方式来处理网络流量&#xff0c;适用于需要进行网络监控、调试和研究的场景。以下是PyShark的一些关键特性和使用方…

团队总结 - Beta版总结会议

在过去的几周中,我们团队共同努力完成了我们的项目。在这次会议中,我们将简要总结我们的成果以及我们仍需要改进的方面。 设想和目标: 解决问题:我们的软件旨在解决已发生或可能发生校园霸凌的问题,我们将基于AI大模型通过和用户的聊天,定点解决用户得心理痛点以及用户学…

探索Docker容器网络

Docker容器已经成为现代应用部署的核心工具。理解Docker的网络模型对于实现高效、安全的容器化应用至关重要。在这篇博客中&#xff0c;我们将深入探讨Docker的网络架构&#xff0c;并通过一些代码例子来揭示其底层实现。 Docker网络模式 Docker提供了多种网络模式&#xff0c…

解决Maven依赖引入不成功的问题

解决Maven依赖引入不成功的问题 确认IntelliJ IDEA中Maven的设置是否正确。 file --> settings --> maven 清除无效的jar&#xff0c;进入本地仓库清除或利用bat工具 以下是bat工具内容&#xff0c;运行即可。【把仓库地址换成你自己的地址进行无效jar包清除】 echo o…