[SwiftUI教程]2、创建和组合视图
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/11032173.html
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
本教程将指导您构建标记 - 一个用于发现和分享您喜爱的地方的iOS应用程序。您将首先构建显示地标详细信息的视图。
为了布局视图,地标使用堆栈来组合和分层图像和文本视图组件。要向视图添加地图,您将包含标准MapKit组件。在细化视图的设计时,Xcode提供实时反馈,以便您可以看到这些更改如何转换为代码。
下载项目文件以开始构建此项目,并按照以下步骤操作。
一、创建一个新项目并探索画布
创建一个使用SwiftUI的新Xcode项目。浏览画布,预览和SwiftUI模板代码。
要预览Xcode中画布中的视图并与之交互,请确保您的Mac正在运行macOS 10.15 beta。
第1步
打开Xcode,在Xcode的启动窗口中单击“ 创建新的Xcode项目”,或选择 File > New > Project.
第2步
在模板选择器中,选择iOS作为平台,选择Single View App模板,然后单击Next。
![](https://img2018.cnblogs.com/blog/960222/201906/960222-20190624150747923-1410077473.png)
第3步
输入“Landmarks”作为Product Name,选择Use SwiftUI复选框,然后单击Next。选择一个位置以在Mac上保存标记项目。
![](https://img2018.cnblogs.com/blog/960222/201906/960222-20190624150813732-1396993016.png)
第4步
在项目导航器中,单击以选中。ContentView.swift
默认情况下,SwiftUI视图文件声明了两种结构。第一个结构符合View
协议并描述视图的内容和布局。第二个结构声明该视图的预览。
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 Text("Hello World") 6 } 7 } 8 9 struct ContentView_Preview: PreviewProvider { 10 static var previews: some View { 11 ContentView() 12 } 13 }
第5步
在画布中,单击“ Resume ”以显示预览。
注意:如果画布不可见,请选择Editor > Editor and Canvas以显示它。
![](https://img2018.cnblogs.com/blog/960222/201906/960222-20190624151114490-1477828705.png)
第6步
在body属性
内,将“Hello World”更改为您自己的问候语。
当您更改视图body
属性中的代码时,预览会更新以反映您的更改。
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 Text("Hello SwiftUI!") 6 } 7 } 8 9 struct ContentView_Preview: PreviewProvider { 10 static var previews: some View { 11 ContentView() 12 } 13 }
二、自定义文本视图
您可以通过更改代码或使用检查器发现可用内容并帮助您编写代码来自定义视图的显示。
在构建标记应用程序时,您可以使用任何编辑器组合:源编辑器,画布或检查器。无论您使用哪种工具,代码都会保持更新。
步骤1
在预览中,按住Command键并单击问候语以显示结构化编辑弹出窗口,然后选择“ 检查”。
弹出窗口显示您可以自定义的不同属性,具体取决于您检查的视图类型。
第1步
在预览中,按住Command键并单击问候语以显示结构化编辑弹出窗口,然后选择“ 检查”。
弹出窗口显示您可以自定义的不同属性,具体取决于您检查的视图类型。
![](https://img2018.cnblogs.com/blog/960222/201906/960222-20190624151557169-306749910.png)
第2步
使用检查器将文本更改为“Turtle Rock”,即您将在应用中显示的第一个地标的名称。
![](https://img2018.cnblogs.com/blog/960222/201906/960222-20190624151618638-1202037749.png)
第3步
将“字体”修改器更改为“ 标题”。
这将系统字体应用于文本,以便它正确响应用户的首选字体大小和设置。
![](https://img2018.cnblogs.com/blog/960222/201906/960222-20190624151637056-582917113.png)
第4步
手动编辑代码以添加color(.green)
修饰符; 这会将文本的颜色更改为绿色。
要自定义SwiftUI视图,请调用称为修饰符的方法。修改器包装视图以更改其显示或其他属性。每个修改器都返回一个新视图,因此链接垂直堆叠的多个修改器是很常见的。
1 ContentView.swift 2 import SwiftUI 3 4 struct ContentView: View { 5 var body: some View { 6 Text("Turtle Rock") 7 .font(.title) 8 .color(.green) 9 } 10 } 11 12 struct ContentView_Preview: PreviewProvider { 13 static var previews: some View { 14 ContentView() 15 } 16 }
您的代码始终是视图的真实来源。当您使用检查器更改或删除修改器时,Xcode会立即更新您的代码以匹配。
第5步
这次,通过Text
在代码编辑器中单击声明来打开检查器,然后从弹出窗口中选择Inspect。单击“ 颜色”弹出菜单,然后选择“ 继承”以再次将文本颜色更改为黑色。
第6步
三、使用堆栈组合视图
除了您在上一部分中创建的标题视图之外,您还将添加文本视图以包含有关地标的详细信息,例如公园的名称和状态。
创建SwiftUI视图时,您可以在视图的body
属性中描述其内容,布局和行为; 但是,该body
属性仅返回单个视图。您可以在堆栈中组合和嵌入多个视图,这些视图将视图水平,垂直或从后到前组合在一起。
在本节中,您将使用垂直堆栈将标题置于包含公园详细信息的水平堆栈上方。
您可以使用Xcode的结构化编辑支持将视图嵌入容器视图,打开检查器或帮助进行其他有用的更改。
![](https://img2018.cnblogs.com/blog/960222/201906/960222-20190624152515576-212672511.png)
第1步
按住Command键并单击文本视图的初始值设定项以显示结构化编辑弹出窗口,然后选择“ 嵌入VStack”。
接下来,您将通过Text
从库中拖动视图来向堆栈添加文本视图。
第2步
单击Xcode窗口右上角的加号按钮(+)打开库,然后Text
在“Turtle Rock”文本视图后立即将视图拖到代码中的位置。
第3步
Text
用Joshua Tree National Park替换视图的占位符文本。自定义位置以匹配所需的布局。
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack { 6 Text("Turtle Rock") 7 .font(.title) 8 Text("Joshua Tree National Park") 9 } 10 } 11 } 12 13 struct ContentView_Preview: PreviewProvider { 14 static var previews: some View { 15 ContentView() 16 } 17 }
第4步
将位置的字体设置为subheadline
。
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack { 6 Text("Turtle Rock") 7 .font(.title) 8 Text("Joshua Tree National Park") 9 .font(.subheadline) 10 } 11 } 12 } 13 14 struct ContentView_Preview: PreviewProvider { 15 static var previews: some View { 16 ContentView() 17 } 18 }
第5步
编辑VStack
初始值设定项以按前导对齐视图。
默认情况下,堆栈将其内容沿其轴居中,并提供适合上下文的间距。
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack(alignment: .leading) { 6 Text("Turtle Rock") 7 .font(.title) 8 Text("Joshua Tree National Park") 9 .font(.subheadline) 10 } 11 } 12 } 13 14 struct ContentView_Preview: PreviewProvider { 15 static var previews: some View { 16 ContentView() 17 } 18 }
接下来,您将在该位置的右侧添加另一个文本视图,这是该公园的状态。
第6步
在画布上,按住Command键点击约书亚树国家公园,然后选择嵌入HStack。
第7步
在位置后添加新文本视图,将占位符文本更改为park的状态,然后将其字体设置为subheadline
。
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack(alignment: .leading) { 6 Text("Turtle Rock") 7 .font(.title) 8 HStack { 9 Text("Joshua Tree National Park") 10 .font(.subheadline) 11 Text("California") 12 .font(.subheadline) 13 } 14 } 15 } 16 } 17 18 struct ContentView_Preview: PreviewProvider { 19 static var previews: some View { 20 ContentView() 21 } 22 }
第8步
要指示布局使用设备的整个宽度,请通过向包含Spacer
两个文本视图的水平堆栈添加a 来分隔park和state 。
甲间隔扩展以使其含有视图中使用它的父视图的空间的所有,而不是具有其大小仅通过其内容来定义。
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack(alignment: .leading) { 6 Text("Turtle Rock") 7 .font(.title) 8 HStack { 9 Text("Joshua Tree National Park") 10 .font(.subheadline) 11 Spacer() 12 Text("California") 13 .font(.subheadline) 14 } 15 } 16 } 17 } 18 19 struct ContentView_Preview: PreviewProvider { 20 static var previews: some View { 21 ContentView() 22 } 23 }
第9步
最后,使用padding()
修改器方法为地标的名称和细节提供一点呼吸空间。
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack(alignment: .leading) { 6 Text("Turtle Rock") 7 .font(.title) 8 HStack { 9 Text("Joshua Tree National Park") 10 .font(.subheadline) 11 Spacer() 12 Text("California") 13 .font(.subheadline) 14 } 15 } 16 .padding() 17 } 18 } 19 20 struct ContentView_Preview: PreviewProvider { 21 static var previews: some View { 22 ContentView()
四、创建自定义图像视图
通过设置名称和位置视图,接下来要做的是为地标添加图像。
您将创建一个自定义视图,将遮罩,边框和阴影应用于图像,而不是在此文件中添加更多代码。
turtlerock.png
![](https://img2018.cnblogs.com/blog/960222/201906/960222-20190624154819323-1698074600.png)
接下来,您将为自定义图像视图创建一个新的SwiftUI视图。
第2步
选择 File > New > File,以再次打开模板选择器 在“ User Interface”部分中,单击以选中“ SwiftUI视图”,然后单击“ Next”。命名文件,然后单击“ Create”。CircleImage.swift
![](https://img2018.cnblogs.com/blog/960222/201906/960222-20190624154935004-235977741.png)
您已准备好插入图像并修改其显示以匹配所需的设计。
第3步
使用Image(_:)
初始化程序将文本视图替换为Turtle Rock的图像。
1 import SwiftUI 2 3 struct CircleImage: View { 4 var body: some View { 5 Image("turtlerock") 6 } 7 } 8 9 struct CircleImage_Preview: PreviewProvider { 10 static var previews: some View { 11 CircleImage() 12 } 13 }
第4步
添加调用以将圆形剪裁形状应用于图像。clipShape(Circle())
的Circle
类型是一个形状,可以通过赋予圆的行程使用作为掩模,或作为视图或填充。
1 import SwiftUI 2 3 struct CircleImage: View { 4 var body: some View { 5 Image("turtlerock") 6 .clipShape(Circle()) 7 } 8 } 9 10 struct CircleImage_Preview: PreviewProvider { 11 static var previews: some View { 12 CircleImage() 13 } 14 }
第5步
创建另一个带有灰色笔触的圆,然后将其添加为叠加层以为图像添加边框。
1 import SwiftUI 2 3 struct CircleImage: View { 4 var body: some View { 5 Image("turtlerock") 6 .clipShape(Circle()) 7 .overlay( 8 Circle().stroke(Color.gray, lineWidth: 4)) 9 } 10 } 11 12 struct CircleImage_Preview: PreviewProvider { 13 static var previews: some View { 14 CircleImage() 15 } 16 }
第6步
接下来,添加半径为10点的阴影。
1 import SwiftUI 2 3 struct CircleImage: View { 4 var body: some View { 5 Image("turtlerock") 6 .clipShape(Circle()) 7 .overlay( 8 Circle().stroke(Color.gray, lineWidth: 4)) 9 .shadow(radius: 10) 10 } 11 } 12 13 struct CircleImage_Preview: PreviewProvider { 14 static var previews: some View { 15 CircleImage() 16 } 17 }
第7步
将边框颜色切换为白色。这样就完成了图像视图。
1 import SwiftUI 2 3 struct CircleImage: View { 4 var body: some View { 5 Image("turtlerock") 6 .clipShape(Circle()) 7 .overlay( 8 Circle().stroke(Color.white, lineWidth: 4)) 9 .shadow(radius: 10) 10 } 11 } 12 13 struct CircleImage_Preview: PreviewProvider { 14 static var previews: some View { 15 CircleImage() 16 } 17 }
五、一起使用UIKit和SwiftUI视图
现在您已准备好创建地图视图。您可以使用MapKit中的类来渲染地图。MKMapView
要UIView
在SwiftUI中使用子类,可以将其他视图包装在符合协议的SwiftUI视图中。SwiftUI包含WatchKit和AppKit视图的类似协议。UIViewRepresentable
首先,您将创建一个可以显示的新自定义视图。MKMapView
MapView.swift
![](https://img2018.cnblogs.com/blog/960222/201906/960222-20190624155504319-1218194655.png)
第2步
为该类型添加import
语句,并声明该类型的一致性。MapKit
UIViewRepresentable
MapView
不要担心Xcode显示的错误; 你将在接下来的几个步骤中解决这个问题。
该协议有你需要添加两个要求:一个是创建一个方法,并且该配置视图和响应任何变化的方法。UIViewRepresentable
makeUIView(context:)
MKMapView
updateUIView(_:context:)
1 import SwiftUI 2 import MapKit 3 4 struct MapView: UIViewRepresentable { 5 var body: some View { 6 Text("Hello World") 7 } 8 } 9 10 struct MapView_Preview: PreviewProvider { 11 static var previews: some View { 12 MapView() 13 } 14 }
第3步
使用创建并返回空body
的方法替换该属性。makeUIView(context:)
MKMapView
1 import SwiftUI 2 import MapKit 3 4 struct MapView: UIViewRepresentable { 5 func makeUIView(context: Context) -> MKMapView { 6 MKMapView(frame: .zero) 7 } 8 } 9 10 struct MapView_Preview: PreviewProvider { 11 static var previews: some View { 12 MapView() 13 } 14 }
第4步
创建一个方法,将地图视图的区域设置为正确的坐标,以使地图在Turtle Rock上居中。updateUIView(_:context:)
当预览处于静态模式时,它们仅完全呈现SwiftUI视图。因为是子类,所以您需要切换到实时预览才能看到地图。MKMapView
UIView
1 import SwiftUI 2 import MapKit 3 4 struct MapView: UIViewRepresentable { 5 func makeUIView(context: Context) -> MKMapView { 6 MKMapView(frame: .zero) 7 } 8 9 func updateUIView(_ view: MKMapView, context: Context) { 10 let coordinate = CLLocationCoordinate2D( 11 latitude: 34.011286, longitude: -116.166868) 12 let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0) 13 let region = MKCoordinateRegion(center: coordinate, span: span) 14 view.setRegion(region, animated: true) 15 } 16 } 17 18 struct MapView_Preview: PreviewProvider { 19 static var previews: some View { 20 MapView() 21 } 22 }
第5步
单击“ 实时预览”按钮可将预览切换为实时模式。您可能需要单击预览上方的“重试”或“ 恢复”按钮。
片刻之后,你会看到Joshua Tree National Park的地图,这是龟背岩的故乡。
六、撰写详细信息视图
您现在拥有了所需的所有组件 - 名称和位置,圆形图像以及位置图。
使用您目前使用的工具,组合您的自定义视图以创建标志性详细视图的最终设计。
第1步
在项目导航器中,选择文件。ContentView.swift
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack(alignment: .leading) { 6 Text("Turtle Rock") 7 .font(.title) 8 HStack { 9 Text("Joshua Tree National Park") 10 .font(.subheadline) 11 Spacer() 12 Text("California") 13 .font(.subheadline) 14 } 15 } 16 .padding() 17 } 18 } 19 20 struct ContentView_Preview: PreviewProvider { 21 static var previews: some View { 22 ContentView() 23 } 24 }
第2步
嵌入一个VStack
将三个文本视图保存在另一个视图中VStack
。
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack { 6 VStack(alignment: .leading) { 7 Text("Turtle Rock") 8 .font(.title) 9 HStack(alignment: .top) { 10 Text("Joshua Tree National Park") 11 .font(.subheadline) 12 Spacer() 13 Text("California") 14 .font(.subheadline) 15 } 16 } 17 .padding() 18 } 19 } 20 } 21 22 struct ContentView_Preview: PreviewProvider { 23 static var previews: some View { 24 ContentView() 25 } 26 }
第3步
将您的自定义添加到堆栈顶部。设置with 的大小。MapView
MapView
frame(width:height:)
仅指定height
参数时,视图会自动调整其内容的宽度。在这种情况下,展开以填充可用空间。MapView
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack { 6 MapView() 7 .frame(height: 300) 8 9 VStack(alignment: .leading) { 10 Text("Turtle Rock") 11 .font(.title) 12 HStack(alignment: .top) { 13 Text("Joshua Tree National Park") 14 .font(.subheadline) 15 Spacer() 16 Text("California") 17 .font(.subheadline) 18 } 19 } 20 .padding() 21 } 22 } 23 } 24 25 struct ContentView_Preview: PreviewProvider { 26 static var previews: some View { 27 ContentView() 28 } 29 }
第4步
单击“ 实时预览”按钮以在组合视图中查看渲染的地图。
您可以在显示实时预览时继续编辑视图。
第5步
将视图添加到堆栈。CircleImage
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack { 6 MapView() 7 .frame(height: 300) 8 9 CircleImage() 10 11 VStack(alignment: .leading) { 12 Text("Turtle Rock") 13 .font(.title) 14 HStack(alignment: .top) { 15 Text("Joshua Tree National Park") 16 .font(.subheadline) 17 Spacer() 18 Text("California") 19 .font(.subheadline) 20 } 21 } 22 .padding() 23 } 24 } 25 } 26 27 struct ContentView_Preview: PreviewProvider { 28 static var previews: some View { 29 ContentView() 30 } 31 }
第6步
要将图像视图叠加在地图视图的顶部,请为图像提供垂直-130个点的偏移量,并从视图底部填充-130个点。
这些调整通过向上移动图像为文本腾出空间。
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack { 6 MapView() 7 .frame(height: 300) 8 9 CircleImage() 10 .offset(y: -130) 11 .padding(.bottom, -130) 12 13 VStack(alignment: .leading) { 14 Text("Turtle Rock") 15 .font(.title) 16 HStack(alignment: .top) { 17 Text("Joshua Tree National Park") 18 .font(.subheadline) 19 Spacer() 20 Text("California") 21 .font(.subheadline) 22 } 23 } 24 .padding() 25 } 26 } 27 } 28 29 struct ContentView_Preview: PreviewProvider { 30 static var previews: some View { 31 ContentView() 32 }
第7步
在外部底部添加垫片,将VStack
内容推到屏幕顶部。
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack { 6 MapView() 7 .frame(height: 300) 8 9 CircleImage() 10 .offset(y: -130) 11 .padding(.bottom, -130) 12 13 VStack(alignment: .leading) { 14 Text("Turtle Rock") 15 .font(.title) 16 HStack(alignment: .top) { 17 Text("Joshua Tree National Park") 18 .font(.subheadline) 19 Spacer() 20 Text("California") 21 .font(.subheadline) 22 } 23 } 24 .padding() 25 26 Spacer() 27 } 28 } 29 } 30 31 struct ContentView_Preview: PreviewProvider { 32 static var previews: some View { 33 ContentView() 34 } 35 }
第8步
最后,要允许地图内容扩展到屏幕的上边缘,请将修改器添加到地图视图中。edgesIgnoringSafeArea(.top)
1 import SwiftUI 2 3 struct ContentView: View { 4 var body: some View { 5 VStack { 6 MapView() 7 .edgesIgnoringSafeArea(.top) 8 .frame(height: 300) 9 10 CircleImage() 11 .offset(y: -130) 12 .padding(.bottom, -130) 13 14 VStack(alignment: .leading) { 15 Text("Turtle Rock") 16 .font(.title) 17 HStack(alignment: .top) { 18 Text("Joshua Tree National Park") 19 .font(.subheadline) 20 Spacer() 21 Text("California") 22 .font(.subheadline) 23 } 24 } 25 .padding() 26 27 Spacer() 28 } 29 } 30 } 31 32 struct ContentView_Preview: PreviewProvider { 33 static var previews: some View { 34 ContentView() 35 } 36 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
· 程序员转型AI:行业分析