SwiftUI六组合复杂用户界面

代码下载

应用的首页是一个纵向滚动的地标类别列表,每一个类别内部是一个横向滑动列表。随后将构建应用的页面导航,这个过程中可以学习到如果组合各种视图,并让它们适配不同的设备尺寸和设备方向。

下载起步项目并跟着本篇教程一步步实践,或者查看本篇完成状态时的工程代码去学习,项目文件。

添加一个首页视图

已经创建了所有在应用中需要的视图,现在给应用创建一个首页视图,把之前创建的视图整合起来。首页不仅仅包含之前创建的视图,它还提供页面间导航的方式,同时也可以展示各种地标信息。
请添加图片描述

创建一个名为CategoryHome.swift的自定义视图文件,添加NavigationSplitView,这个NavigationSplitView将会容纳应用中其它不同的视图。配合使用NavigationLink及相关的修改器,就可以构建出应用的页面间导航结构,设置导航栏标题为Featured:

struct CategoryHome: View {var body: some View {NavigationSplitView {Text("Hello, World!").navigationTitle("Featured")} detail: {Text("Select a Landmark")}}
}

创建地标类别列表

应用为了便于用户浏览各种类别的地标,将地标按类别竖向排列形成列表视图,对于每一个类别内的具体地标,又把它们按照水平方向排列,形成横向列表。组合使用垂直栈(vertical statck)和水平栈(horizontal stack)并给列表添加滚动。
请添加图片描述

首先从landmarkData.json文件读取类别数据。

1、在Landmark中,向Landmark结构添加Category枚举和category属性。landmarkData文件已经为每个地标数据包含了一个category值,该类别值为三个字符串值之一。通过匹配数据文件中的名称,可以让结构体遵守Codable协议来加载数据:

struct Landmark: Hashable, Codable, Identifiable {var id: Intvar name: Stringvar park: Stringvar state: Stringvar description: Stringvar isFavorite: Boolvar category: Categoryenum Category: String, CaseIterable, Codable {case lakes = "Lakes"case rivers = "Rivers"case mountains = "Mountains"}private var imageName: Stringvar image: Image {Image(imageName)}private var coordinates: Coordinatesvar locationCoordinate: CLLocationCoordinate2D {CLLocationCoordinate2D(latitude: coordinates.latitude,longitude: coordinates.longitude)}struct Coordinates: Hashable, Codable {var latitude: Doublevar longitude: Double}
}

2、在ModelData中,添加一个categories计算字典,使用Dictionary结构体的初始化方法init(grouping:by:),把地标数据的类别属性category传入作为分组依据,可以把地标数据按类别分组:

class ModelData {var landmarks: [Landmark] = load("landmarkData.json")var hikes: [Hike] = load("hikeData.json")var categories: [ String: [Landmark] ] {Dictionary(grouping: landmarks) { $0.category.rawValue }}
}

3、在CategoryHome中创建一个modelData属性。现在需要访问categories,稍后还需要访问其他landmark数据。使用List显示地标数据的类别。Landmark.Category是枚举类型,它的值标识列表中每一种类别,可以保证类别不会有重复定义:

struct CategoryHome: View {@Environment(ModelData.self) var modelData: ModelDatavar body: some View {NavigationSplitView {List {ForEach(modelData.categories.keys.sorted(), id: \.self) { key inText(key)}}.navigationTitle("Featured")} detail: {Text("Select a Landmark")}}
}#Preview {CategoryHome().environment(ModelData())
}

创建地标行

Landmarks在水平滚动的一行中显示每个类别。添加一个新的视图类型来表示行,然后在新视图中显示该类别的所有地标。

重用在创建和组合视图中创建的Landmark视图的部分,以创建熟悉的Landmark预览。

请添加图片描述

1、创建一个名为CategoryItem的新自定义视图,显示一个地标:

struct CategoryItem: View {var landmark: Landmarkvar body: some View {VStack(alignment: .leading) {landmark.image.resizable().frame(width: 155, height: 155).cornerRadius(5)Text(landmark.name).font(.caption)}.padding(.leading, 15)}
}#Preview {CategoryItem(landmark: ModelData().landmarks[0])
}

2、定义一个新的视图类型CategoryRow,用来展示地标类别行的内容。新建行视图需要存放地标具体类别的展示数据。在CategoryRow.swift中将类别的条目放入HStack中,并将其与类别名称分组到VStack中。为行内容指定一个高度,并把行内容嵌入到ScrollView中,以支持横向滑动。预览视图时,可以多增加几个地标数据,用来查看列表的滑动是否正常:

struct CategoryRow: View {var categoryName: Stringvar items: [Landmark]var body: some View {VStack(alignment: .leading) {Text(categoryName).font(.headline).padding(.leading, 15).padding(.top, 5)ScrollView(.horizontal, showsIndicators: false) {HStack(alignment: .top, spacing: 0) {ForEach(items) { landmark inCategoryItem(landmark: landmark)}}}.frame(height: 185)}}
}#Preview {let landmarks = ModelData().landmarksreturn CategoryRow(categoryName: landmarks[0].category.rawValue, items: Array(landmarks.prefix(3)))
}

完成类别视图

将行和特色地标图像添加到类别主页。

1、更新CategoryHome的body,将类别信息传递给行类型的实例:

接下来,在视图的顶部添加一个特色地标。要做到这一点,需要从地标数据中获得更多信息。

2、在Landmark中,添加一个新的isFeatured属性,与添加的其他地标属性一样,这个布尔值已经存在于数据中,只需要声明一个新属性:

struct Landmark: Hashable, Codable, Identifiable {var id: Intvar name: Stringvar park: Stringvar state: Stringvar description: Stringvar isFavorite: Boolvar isFeatured: Boolvar category: Categoryenum Category: String, CaseIterable, Codable {case lakes = "Lakes"case rivers = "Rivers"case mountains = "Mountains"}private var imageName: Stringvar image: Image {Image(imageName)}private var coordinates: Coordinatesvar locationCoordinate: CLLocationCoordinate2D {CLLocationCoordinate2D(latitude: coordinates.latitude,longitude: coordinates.longitude)}struct Coordinates: Hashable, Codable {var latitude: Doublevar longitude: Double}
}

3、在ModelData中,添加一个新的计算特色地标数组,其中只包含将isFeatured设置为true的地标:

class ModelData {var landmarks: [Landmark] = load("landmarkData.json")var hikes: [Hike] = load("hikeData.json")var categories: [ String: [Landmark] ] {Dictionary(grouping: landmarks) { $0.category.rawValue }}var features: [Landmark] {landmarks.filter { $0.isFeatured }}
}

4、在CategoryHome中,将第一个特色地标的图像添加到列表的顶部。在后面的教程中,会将这个视图修改成一个交互式轮播图。目前,这个视图仅仅展示一张缩放和剪裁后的地标图片。把视图的边距设置为0,让展示内容可以尽量贴着屏幕边沿:

struct CategoryHome: View {@Environment(ModelData.self) var modelData: ModelDatavar body: some View {NavigationSplitView {List {modelData.features[0].image.resizable().frame(height: 200).clipped().listRowInsets(EdgeInsets())ForEach(modelData.categories.keys.sorted(), id: \.self) { key inCategoryRow(categoryName: key, items: modelData.categories[key] ?? [])}.listRowInsets(EdgeInsets())}.navigationTitle("Featured")} detail: {Text("Select a Landmark")}}
}

在各节之间添加导航

现在所有类别的地标都可以在首页视图中展示出来,用户还需要能够进入应用其它页面的方法。使用页面导航和相关API来实现用户从应用首页到地标详情页、收藏列表页及用户个人中心页的跳转。

请添加图片描述

1、在CategoryRow.swift中,把CategoryItem视图包裹在NavigationLink视图中。CategoryItem这时做为跳转按钮的内容,destination指定点击NavigationLink按钮时要跳转的目标视图:

struct CategoryRow: View {var categoryName: Stringvar items: [Landmark]var body: some View {VStack(alignment: .leading) {Text(categoryName).font(.headline).padding(.leading, 15).padding(.top, 5)ScrollView(.horizontal, showsIndicators: false) {HStack(alignment: .top, spacing: 0) {ForEach(items) { landmark inNavigationLink(destination: LandmarkDetail(landmark: landmark)) {CategoryItem(landmark: landmark)}}}}.frame(height: 185)}}
}

2、使用renderingMode(:)和foregroundColor(:)这两个属性修改器来改变地标类别项的导航样式。做为NavigationLink标签的CategoryItem中的文本会使用Environment中的强调颜色,图片可能以模板图片的方式渲染,这些都可以使用属性修改器来调整,达到最佳效果:

struct CategoryItem: View {var landmark: Landmarkvar body: some View {VStack(alignment: .leading) {landmark.image.renderingMode(.original).resizable().frame(width: 155, height: 155).cornerRadius(5)Text(landmark.name).foregroundStyle(.primary).font(.caption)}.padding(.leading, 15)}
}

3、接下来,将修改应用程序的ContentView,以显示一个TabView,让用户在刚刚创建的类别视图和现有的地标列表之间进行选择:

  • 切换到ContentView并添加要显示的选项卡枚举。为选项卡选择添加一个状态变量,并给它一个默认值。
  • 创建一个TabView来包装LandmarkList和新的CategoryHome。每个视图上的 tag(_😃 修饰符匹配选择属性可以取的一个可能值,因此当用户在用户界面中进行选择时,TabView可以协调显示哪个视图。
  • 给每个Tab一个标签。确保实时预览打开,并尝试新的导航。
struct ContentView: View {@State private var selection: Tab = .featuredenum Tab {case featuredcase list}var body: some View {TabView(selection: $selection) {CategoryHome().tabItem { Label("Featured", systemImage: "star") }.tag(Tab.featured)LandmarkList().tabItem { Label("List", systemImage: "list.bullet") }.tag(Tab.list)}}
}#Preview {ContentView().environment(ModelData())
}

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

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

相关文章

【C语言训练题库】扫雷->简单小游戏!

🔥博客主页🔥:【 坊钰_CSDN博客 】 欢迎各位点赞👍评论✍收藏⭐ 目录 1. 题目 2. 解析 3. 代码 4. 小结 1. 题目 小sun上课的时候非常喜欢玩扫雷。他现小sun有一个初始的雷矩阵,他希望你帮他生成一个扫雷矩阵。 扫雷…

Vue3_对接腾讯云COS_大文件分片上传和下载

目录 一、腾讯云后台配置 二、安装SDK 1.script 引入方式 2.webpack 引入方式 三、文件上传 1.new COS 实例 2.上传文件 四、文件下载 腾讯云官方文档: 腾讯云官方文档https://cloud.tencent.com/document/product/436/11459 一、腾讯云后台配置 1.登录 对…

Codeforces Round 951 (Div. 2) F. Kostyanych‘s Theorem(思维题 交互好题)

题目 交互题&#xff0c;n&#xff08;n<1e5&#xff09;个点的完全图&#xff0c;无向的&#xff0c;初始恰好删了n-2条边 每次询问可以输入一个d&#xff1a;? d 交互器会输出一个当前度>d的点v&#xff0c; 如果有多个这样的点&#xff0c;输出度最小的&#xff…

【CS.CN】优化HTTP传输:揭示Transfer-Encoding: chunked的奥秘与应用

文章目录 0 序言0.1 由来0.2 使用场景 1 Transfer-Encoding: chunked的机制2 语法 && 通过设置Transfer-Encoding: chunked优化性能3 总结References 0 序言 0.1 由来 Transfer-Encoding头部字段在HTTP/1.1中被引入&#xff0c;用于指示数据传输过程中使用的编码方式…

InternLM-XComposer2-4KHD开拓性的4K高清视觉-语言模型

大型视觉-语言模型&#xff08;LVLM&#xff09;在图像字幕和视觉问答&#xff08;VQA&#xff09;等任务中表现出色。然而&#xff0c;受限于分辨率&#xff0c;这些模型在处理包含细微视觉内容的图像时面临挑战。 分辨率的限制严重阻碍了模型处理含有丰富细节的图像的能力。…

网络空间安全数学基础·多项式环与有限域

5.1 多项式环&#xff08;掌握&#xff09; 5.2 多项式剩余类环&#xff08;理解&#xff09; 5.3 有限域&#xff08;熟练&#xff09; 5.1 多项式环 定义&#xff1a;设F是一个域&#xff0c;称是F上的一元多项式&#xff0e; 首项&#xff1a;如果an≠0&#xff0c;则称 a…

【Python】认识 Python

一、计算机基础概念 1、什么是计算机 很多老一辈的人&#xff0c;管下面这个叫做计算机。然而&#xff0c;它只是 “计算器”&#xff0c;和计算机是有很大区别的。 现在我们所说的计算机&#xff0c;不光能进行算术运算&#xff0c;还能进行逻辑判断、数据存储、网络通信等…

Qt之QGraphicsView —— 笔记3:矩形图元连接(附完整源码)

效果 完整源码 注意:在ui文件中拖入一个QGraphicsView类窗口控件,然后用MyGraphicsView提升该类。 main.cpp #include "widget.h" #include <QApplication>int main(

【背包-BM70 兑换零钱(一)】

题目 BM70 兑换零钱(一) 描述 给定数组arr&#xff0c;arr中所有的值都为正整数且不重复。每个值代表一种面值的货币&#xff0c;每种面值的货币可以使用任意张&#xff0c;再给定一个aim&#xff0c;代表要找的钱数&#xff0c;求组成aim的最少货币数。 如果无解&#xff0c;…

《数据结构》

简答题 一、设散列函数H(key)=key MOD 11,用线性探测再散列法解决冲突。对关键字序列{ 13,28,72,5,16,18,7,11,24 }在地址空间为0-10的散列区中建散列表,画出此表,并求等概率情况下查找成功时的平均查找长度。 散列函数为 H(key)=key MOD 11,将关键字序列 {13,28,…

width: 100%和 width: 100vw这两种写法有什么区别

width: 100%; 和 width: 100vw; 是两种不同的 CSS 写法&#xff0c;它们在实际应用中会有不同的效果。以下是这两种写法的主要区别&#xff1a; width: 100%; 定义&#xff1a;将元素的宽度设置为其包含块&#xff08;通常是父元素&#xff09;宽度的 100%。效果&#xff1a;元…

计算机毕业设计hadoop+spark+hive知识图谱股票推荐系统 股票数据分析可视化大屏 股票基金爬虫 股票基金大数据 机器学习 大数据毕业设计

哈 尔 滨 理 工 大 学 毕业设计中期检查报告 题 目&#xff1a;基于Spark的股票大数据分析及可视化系统 院 系&#xff1a; 计算机科学与技术学院 数据科学与大数据技术 姓 名&#xff1a; 鲍方博 指导教师&…

品牌策划:不只是工作,是一场创意与学习的旅程

你是否认为只有那些经验丰富、手握无数成功案例的高手才能在品牌策划界崭露头角&#xff1f; 今天&#xff0c;我要悄悄告诉你一个行业内的秘密&#xff1a;在品牌策划的世界里&#xff0c;经验虽重要&#xff0c;但绝非唯一。 1️、无止境的学习欲望 品牌策划&#xff0c;这…

JAVA-LeetCode 热题-第24题:两两交换链表中的节点

思路&#xff1a; 定义三个指针&#xff0c;其中一个临时指针&#xff0c;进行交换两个节点的值&#xff0c;重新给临时指针赋值&#xff0c;移动链表 class Solution {public ListNode swapPairs(ListNode head) {ListNode pre new ListNode(0,head);ListNode temp pre;wh…

递归(全排列andN皇后)

全排列 分治与递归 递归是实现分治的一种方法 思想思路 题目&#xff1a; 全排列i 我这样直接输出会多输出一个空行&#xff08;最后一个\n&#xff09; #include<stdio.h>using namespace std; const int maxn10; int an[maxn]; int n; bool hash[maxn]{0}; int c0…

wx小程序自定义tabbar

1.在app.json文件中&#xff0c;添加自定义tabbar配置&#xff1a;"custom": true "tabBar": {"custom": true,"backgroundColor": "#fafafa","borderStyle": "white","selectedColor": &quo…

“开源与闭源:AI大模型发展的未来之路“

文章目录 每日一句正能量前言数据隐私开源大模型与数据隐私闭源大模型与数据隐私数据隐私保护的共同考虑结论 商业应用开源大模型的商业应用优势&#xff1a;开源大模型的商业应用劣势&#xff1a;闭源大模型的商业应用优势&#xff1a;闭源大模型的商业应用劣势&#xff1a;商…

虚拟机与windows文件同步

如果上图中不能设置&#xff0c;则在虚拟机mnt文件夹执行以下命令&#xff1a;

Go微服务: 分布式之TCC事务

TCC 分布式事务 T: Try 预处理, 尝试执行&#xff0c;完成所有的业务检查&#xff0c;做好一致性&#xff0c;预留必要的业务资源&#xff0c;做好准隔离性C: Confirm 确认&#xff0c;如果所有的分支Try都成功了, 就到了这个阶段, Confirm 是真正执行业务的过程, 不做任何业务…

【数据结构】图论入门

引入 数据的逻辑结构&#xff1a; 集合&#xff1a;数据元素间除“同属于一个集合”外&#xff0c;无其他关系线性结构&#xff1a;一个对多个&#xff0c;例如&#xff1a;线性表、栈、队列树形结构&#xff1a;一个对多个&#xff0c;例如&#xff1a;树图形结构&#xff1…