iOS swiftUI 创建 macos图片 1.1
第六节 组合列表视图与过滤器视图
创建一个组列过滤器和列表的视图。为过滤器提供新的状态信息,同时绑定地标选择到主视图的父视图上。
步骤1 项目中添加一个新的SwiftUI
视图,命名为NavigationPrimary.swift
。
步骤2 声明一个FilterType
状态。这个状态会被绑定到过滤器和列表视图中。
步骤3 添加过滤器视图并绑定FilterType
状态。现在预览是失败的,因为过滤器依赖环境中的用户数据,下一步会处理这块儿。
步骤4 注入用户数据对角到环境中。导航主视图是不直接需要用户数据的,但它的子视图需要。为了可以进行预览,把用户数据作为环境对象注入到导航主视图中。
步骤5 添加一个绑定到当前选中地标的关系。
步骤6 添加地标列表视图,并把它绑定到选中的地标和过滤器状态上。预览视图中选中第二个选项,因为输入数据是landmarkData[1]
作为用户选中的地标输入数据。
步骤7 限制导航视图的宽度,防止用户让它变的太宽或太窄。
第七节 复用CircleImage
有时只需要经过稍微修改,就可以跨平台复用一些视图。当构建macOS
平台的地标详情页视图时,会复用iOS
版地标应用中的CircleImage
视图。为了适配macOS
平台下的不同布局要求,会添加一个参数来控件阴影半径。
步骤1 在项目导航栏中选中Landmarks
-> Supporting Views
并选择CircleImage.swift
文件。
步骤2 把CircleImage.swift
文件添加到时MacLandmarks
编译目标。
步骤3 在CircleImage.swift
文件中,修改结构体,使用新的阴影半径参数。通过给新参数提供默认值,可以确保iOS
和watchOS
平台的应用都能与原来保持一致,同时还能在macOS
平台上使用。
第八节 为macOS
扩展MapView
类似于CircleImage
,这里要在macOS
上复用MapView
。然而,MapView
要做更大的改动,因为MapView
使用的是MapKit
依赖于UIKit
框架。在macOS
平台上使用MapKit
需要依赖于AppKit
框架,所以需要添加编译器指令,让编译过程在macOS
目标上进行正确的依赖。
步骤1 在项目导航器中,选择Landmarks
-> Supporting Views
,选中MapView.swift
文件。
步骤2 把MapView.swift
文件添加到MacLandmarks
编译目标上。此时Xcode
会报错,因为MapView
使用了UIViewRepresentable
协议,这个协议在macOS SDK
里是没有的。下面的步骤中,会使用NSViewRepresentable
协议来扩展MapView
,让它能在macOS
平台上使用。
步骤3 插入条件编译指令,用来指定特定平台行为。用条件编译的两个条件分支把协议UIViewRepresentable
和NSViewRepresentable
协议的遵循分开。
步骤4 使用条件编译,把在iOS
平台上要实现的协议UIViewRepresentable
及协议方法makeUIView
、updateUIView
放在MapView
的扩展实现中,这样就把MapKit
的平台依赖性解耦了。
步骤5 添加在macOS
平台上的NSViewRepresentable
协议遵循。与UIViewRepresentable
协议一样,NSViewRepresentable
协议的实现也可以使用主类中的方法。
第九节 构建详情视图
详情视图展示用户选中的地标信息。创建一个类似iOS
平台地标应用的地标详情视图,不同之处在于,macOS
平台有不同的数据表示方法,这就需要针对macOS
平台对详情视图作一些裁剪,复用一些之前调整过的视图。
步骤1 项目中添加一个新的视图,命名为NavigationDetail.swift
,并添加一个landmark
属性。初始化详情视图时会使用landmark
属性来指定详情页展示的地标信息。
步骤2 在NavigationDetail.swift
内部创建一个滚动视图,滚动视图中包含一个VStack
,VStack
中又包含一个HStack
,HStack
中展示关于地标的图片CircleImage
及Text
地标文本信息。通过设置VStack
的最大最小宽度,确保展示的内容保持一定的宽度,以适合用户阅读。跨平台复用视图是非常方便的,定制一下CircleImage
视图,以满足当前的布局要求。
步骤3 把输入的图片变为可缩放,并设置图片按视图大小展示,这样可以让CircleImage
视图的大小与Text
块文本的大小看上去比较匹配。这种修改方法不需要调整CircleImage
的内部实现。
步骤4 调整阴影半径,以匹配更小的图片。这个修改依赖之前对CircleImage
视图所作的参数化改造。
用户使用按钮标记一个地标是否被收藏。为了让这个动作生效,需要访问用户数据中的对应变量。
步骤5 添加用户数据对应的环境对象,并创建一个基于当前选中地标的存储属性landmarkIndex
步骤6 添加一个按钮,水平方式对齐地标名称,使用星星图标,并在点击时可以切换用户对这个地标的收藏状态。当用户修改地标数据时,在用户数据中查找被修改的地标数据,并用最新的数据更新原来的数据,让数据保持最新状态。
步骤7 在分割区载下再添加一个地标的信息,对应数据中新增的字段description
。
预览视图中标题块会被挤到左边,因为描述内容比较多,把水平方向的宽度撑满了。
步骤8 在详情视图顶部插入地图,调整地图的偏移,让地图和其它内容有一定区域的重叠。地图占满视图全宽,因此会把详情文本挤到预览视图的底部看不到的位置,但它实际上是存在的。
步骤9 导入MapKit
并添加一个Open in Maps
的按钮,当按钮被点击时,打开地图应用并定位到地标位置。
步骤10 把Open in Maps
按钮叠放在地图的右下角。
第十节 把主视图和详情视图组合起来
已经构建了所有的视图元素,把主视图和详情视图组合起来,共同构成ContentView
。
步骤1 在MacLandmarks
文件夹中,选择ContentView.swift
文件。
步骤2 为选中的地标设置对应的属性selectedLandmark
,并用@State
属性标识为状态属性。使用可选类型定义selectedLandmark
,可以不用为它设置默认值。因此,无论是预览视图还是应用初始化时,都可以不需要用户选中地标进行渲染。
步骤3 把用户数据作为环境对象注入。ContentView
本身不会直接依赖用户数据,但它的子视图需要访问用户数据。对于预览视图来说,为了正常预览和编译成功,ContentView
需要获取用户数据。
步骤4 在AppDelegate.swift
中,为ContentView
注入环境对象,这样可以让它的子视图访问到用户数据,应用也可以编译成功。
步骤5 在ContentView
中添加NavigationView
作为顶级视图,并设置一个最小尺寸。
步骤6 添加主视图,展示选中的地标。当用户选中地标列表中的某个地标时,被选中的地标数据就会被赋值到selectedLandmark
属性上。
步骤7 添加详情视图,详情视图不接收可选地标数据, 因些传入详情视图的地标数据需要确保不为空。用户选中地标前,地标详情视图不会渲染,这就是为会预览视图没有任何改变,还是和之前一样。
步骤8 构建并运行应用。尝试改变过滤器的设置,或者点击详情页中的收藏按钮,观察视图内容的变化。