创建并组合视图-CreatingAndCombiningViews
本教程将指导你构建一个用于发现和分享你所喜爱地方的iOS应用—— “Landmarks” 。你将从构建显示地标细节的视图开始。
为了布置视图,“Landmarks” 使用 stacks 来组合和分层图像和文本视图组件。要在视图中添加地图,你将包含一个标准的 MapKit 组件。当您完善视图的设计时,Xcode会提供实时反馈,这样您就可以看到这些变化是如何转化为代码的。
下载项目文件以开始构建这个项目,并按照以下步骤进行。
This tutorial guides you through building_Landmarks— an iOS app for discovering and sharing the places you love. You’ll start by building the view that shows a landmark’s details.
To lay out the views, Landmarks uses stacks to combine and layer the image and text view components. To add a map to the view, you’ll include a standard MapKit component. As you refine the view’s design, Xcode provides real-time feedback so you can see how those changes translate into code.
Download the project files to begin building this project, and follow the steps below.
创建一个新项目并探索画布-Create a New Project and Explore the Canvas
创建一个使用SwiftUI的新Xcode项目。探索画布、预览和SwiftUI模板代码。
要在Xcode中预览画布并与画布中的视图进行交互,请确保您的Mac正在运行macOS Catalina 10.15。
Create a new Xcode project that uses SwiftUI. Explore the canvas, previews, and the SwiftUI template code. To preview and interact with views from the canvas in Xcode, ensure your Mac is running macOS Catalina 10.15.
- 第一步
打开Xcode,在Xcode的启动窗口中点击Create a new Xcode project,或者选择File > New > Project。
- 第二步
在模板选择器中,选择iOS为平台,选择Single View App模板,然后点击Next。
- 第三步
输入 "Landmarks "作为工程名称,选择SwiftUI作为用户界面,然后点击Next。在Mac上选择保存Landmarks项目的位置。
- 第四步
在项目导航器中,选择ContentView.swift。
默认情况下,SwiftUI视图文件会声明两个结构。第一个结构符合View协议,描述了视图的内容和布局。第二个结构声明了该视图的预览。
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello World")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
- 第五步
在画布中,点击 Resume(恢复) 显示预览。
技巧
如果画布不可见,选择 Editor > Editor and Canvas 来显示它。
第六步
在bodyproperty中,将 "Hello World "改为自己的问候语。
当您更改视图的body属性中的代码时,预览会更新以反映你的更改。
Step 1
Open Xcode and either clickCreate a new Xcode projectin Xcode’s startup window, or chooseFile > New > Project.
Step 2
In the template selector, selectiOSas the platform, select theSingle View Apptemplate, and then clickNext.
Step 3
Enter “Landmarks” as the Product Name, selectSwiftUIfor the user interface, and clickNext. Choose a location to save the Landmarks project on your Mac.
Step 4
In the Project navigator, select
ContentView.swift.By default, SwiftUI view files declare two structures. The first structure conforms to the
Viewprotocol and describes the view’s content and layout. The second structure declares a preview for that view.Step 5
In the canvas, clickResumeto display the preview.
Tip
If the canvas isn’t visible, selectEditor > Editor and Canvasto show it.
Step 6
Inside the
bodyproperty, change “Hello World” to a greeting for yourself.As you change the code in a view’s
bodyproperty, the preview updates to reflect your changes.
设置文本视图-Customize the Text View
您可以通过更改代码来定制视图的显示,或者使用检查器来发现可用的内容并帮助您编写代码。
当你构建Landmarks应用时,你可以结合使用任何一种编辑器:源码编辑器、画布或检查器。无论你使用哪种工具,你的代码都会保持更新。
接下来,你将使用检查器自定义文本视图。
You can customize a view’s display by changing your code, or by using the inspector to discover what’s available and to help you write code.
As you build the Landmarks app, you can use any combination of editors: the source editor, the canvas, or the inspectors. Your code stays updated, regardless of which tool you use.
Next, you’ll customize the text view using the inspector.
- 第一步
在预览中,Command-点击问候语,弹出结构化编辑弹窗,选择 Inspect(检查) 。
| 译者注 |
|---|
| control-option-点击可以直接打开Inspect |
弹出式菜单显示了不同的属性,您可以根据您检查的视图类型进行自定义。
- 第二步
使用检查器将文本更改为 "Turtle Rock",这是您将在应用程序中显示的第一个地标的名称。
- 第三步
将字体修饰符改为 Title 。
这将系统字体应用于文本,以便它正确响应用户的首选字体大小和设置。
要自定义SwiftUI视图,你可以调用称为 修改器(modifiers) 的方法。修改器对视图进行封装,以改变其显示或其他属性。每一个修改器都会返回一个新的视图,所以通常连续使用多个修改器,并将它们纵向堆叠。
- 第四步
手工编辑代码,添加foregroundColor(.green)修改器,将文字的颜色改为绿色。
视图永远是你代码的真实反映。当你使用检查器更改或删除一个修改器时,Xcode会立即更新并匹配你的代码。
- 第五步
这次,在代码编辑器中按下Command-点击Text,打开检查器,然后从弹出的菜单中选择Inspect。点击Color弹出菜单,选择Inherited(继承),将文字颜色再次改为黑色。
- 第六步
注意,Xcode会自动更新你的代码以反映变化,删除foregroundColor(.green)修改器。
//
// ContentView.swift
// Landmarks
//
// Created by EchoSun on 2020/12/18.
//
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Turtle Rock")
.font(.title)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Next, you’ll customize the text view using the inspector.
Step 1
In the preview, Command-click the greeting to bring up the structured editing popover, and chooseInspect.
The popover shows different attributes that you can customize, depending on the type of view you inspect.
Step 2
Use the inspector to change the text to “Turtle Rock”, the name of the first landmark you’ll show in your app.
Step 3
Change the Font modifier toTitle.
This applies the system font to the text so that it responds correctly to the user’s preferred font sizes and settings.
To customize a SwiftUI view, you call methods called_modifiers_. Modifiers wrap a view to change its display or other properties. Each modifier returns a new view, so it’s common to chain multiple modifiers, stacked vertically.
Step 4
Edit the code by hand to add the
foregroundColor(.green)modifier; this changes the text’s color to green.Your code is always the source of truth for the view. When you use the inspector to change or remove a modifier, Xcode updates your code immediately to match.
Step 5
This time, open the inspector by Command-clicking on the
Textdeclaration in the code editor, and then chooseInspectfrom the popover. Click theColorpop-up menu and chooseInheritedto change the text color to black again.Step 6
Notice that Xcode updates your code automatically to reflect the change, removing the
foregroundColor(.green)modifier.
使用堆栈组合视图-Combine Views Using Stacks
除了上一节中创建的标题视图外,您还将添加文本视图来包含有关地标的详细信息,例如公园名称和它所处的位置。
当创建SwiftUI视图时,您可以在视图的body属性中描述它的内容、布局和行为;但是,body属性只返回一个视图。您可以在 堆栈(stacks) 中组合和嵌入多个视图,将视图水平、垂直或从后到前地组合在一起。
在本节中,你将使用水平堆栈放置公园的细节,并将它和标题放置到一个垂直堆栈上。
Beyond the title view you created in the previous section, you’ll add text views to contain details about the landmark, such as the name of the park and state it’s in.
When creating a SwiftUI view, you describe its content, layout, and behavior in the view’s
bodyproperty; however, thebodyproperty only returns a single view. You can combine and embed multiple views in stacks , which group views together horizontally, vertically, or back-to-front.In this section, you’ll use a vertical stack to place the title above a horizontal stack that contains details about the park.
您可以使用Xcode的结构化编辑支持,将一个视图嵌入到容器视图中,打开一个检查器,或帮助进行其他有用的更改。
- 第1步
命令点击文本视图的初始化器,显示结构化编辑弹出器,然后选择Embed in VStack。
接下来,你将通过从库中拖动一个Textview来添加一个文本视图到堆栈中。
- 第二步
点击Xcode窗口右上方的加号按钮(+)打开库,然后拖动一个Text的view到代码中紧挨着 "Turtle Rock "文本视图的地方。
| 译者注 |
|---|
| 使用 library 窗口快速添加控件的快捷键: ⇧⌘ L |
- 第三步
将Text的占位文字替换为Joshua Tree National Park。
然后自定义位置以匹配所需的布局。
- 第四步
将该位置的字体设置为subheadline。
- 第五步
编辑 "VStack "初始化器使视图沿前缘对齐。
默认情况下,堆栈将其内容沿其轴线居中,并为上下文设置适当的间距。
接下来,您将在位置的右侧添加另一个文本视图,这是公园的位置。
- 第六步
在画布中,命令点击Joshua Tree National Park,并选择Embed in HStack(嵌入到HStack中)。
- 第七步
在位置后面添加一个新的文本视图,将占位文字改为公园的位置,然后将其字体设置为subheadline。
- 第八步
为了使布局填充设备的整个宽度,我们在包含两个文本视图的水平堆栈中添加一个 "间隔器 (Spacer)"来分离公园和位置。
间隔器 (Spacer) 将占据其父视图的所有空间,而不是仅由其内容决定其大小。
- 第九步
最后,使用padding()修改器方法给地标的名称和细节多一点空间。
//
// ContentView.swift
// Landmarks
//
// Created by EchoSun on 2020/12/18.
//
import SwiftUI
struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
.padding() // 增加四周的空间
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
You can use Xcode’s structured editing support to embed a view in a container view, open an inspector, or help with other useful changes.
Step 1
Command-click the text view’s initializer to show the structured editing popover, and then chooseEmbed in VStack.
Next, you’ll add a text view to the stack by dragging a
Textview from the library.Step 2
Open the library by clicking the plus button (+) at the top-right of the Xcode window, and then drag a
Textview to the place in your code immediately after the “Turtle Rock” text view.Step 3
Replace the
Textview’s placeholder text withJoshua Tree National Park.Customize the location to match the desired layout.
Step 4
Set the location’s font to
subheadline.Step 5
Edit the
VStackinitializer to align the views by their leading edges.By default, stacks center their contents along their axis and provide context-appropriate spacing.
Next, you’ll add another text view to the right of the location, this for the park’s state.
Step 6
In the canvas, Command-clickJoshua Tree National Park, and chooseEmbed in HStack.
Step 7
Add a new text view after the location, change the placeholder text to the park’s state, and then set its font to
subheadline.Step 8
To direct the layout to use the full width of the device, separate the park and the state by adding a
Spacerto the horizontal stack holding the two text views.A spacer expands to make its containing view use all of the space of its parent view, instead of having its size defined only by its contents.
Step 9
Finally, use the
padding()modifier method to give the landmark’s name and details a little more space.
创建图片视图-Create a Custom Image View
名称和位置视图都设置好了,下一步就是为地标添加图像。
在这个文件中,您将创建一个自定义视图,为图像应用遮罩、边框和阴影,而不是添加更多代码。
With the name and location views all set, the next step is to add an image for the landmark.
Instead of adding more code in this file, you’ll create a custom view that applies a mask, border, and drop shadow to the image.
从添加图像到项目的资产目录开始。
- 第一步
在项目文件的 Resources(资源) 文件夹中找到turtlerock.png,并将其拖入资产(Assets)目录的编辑器中。Xcode将为该图像创建一个新的图像集。
接下来,你将为你的自定义图像视图创建一个新的SwiftUI视图。
- 第二步
选择File > New > File,再次打开模板选择器。在User Interface部分,选择SwiftUI View,点击Next。将文件命名为CircleImage.swift并点击Create。
你已经准备好插入图片并修改其显示方式以符合所需的设计。
- 第三步
使用Image(_:)初始化器将文本视图替换为Turtle Rock的图像。
- 第四步
添加一个clipShape(Circle()),在图像上剪裁出一个圆形。
Circle 类型是一个形状,你可以用它来做蒙版,或者通过给圆圈一个描边或填充来做视图。
- 第五步
用灰色笔触创建另一个圆圈,然后将其添加为叠加,给图像一个边框。
- 第六步
接下来,添加一个半径为10点的阴影。
- 第七步
将边框颜色切换为白色。
这样就完成了图像视图。
//
// CircleImage.swift.swift
// Landmarks
//
// Created by EchoSun on 2020/12/18.
//
import SwiftUI
struct CircleImage: View {
var body: some View {
Image("turtlerock")
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 4))
.shadow(radius: 10)
}
}
struct CircleImage_Previews: PreviewProvider {
static var previews: some View {
CircleImage()
}
}
Start by adding an image to the project’s asset catalog.
Step 1
Find
turtlerock.pngin the project files’Resourcesfolder; drag it into the asset catalog’s editor. Xcode creates a new image set for the image.Next, you’ll create a new SwiftUI view for your custom image view.
Step 2
ChooseFile > New > Fileto open the template selector again. In theUser Interfacesection, selectSwiftUI Viewand clickNext. Name the file
CircleImage.swiftand clickCreate.You’re ready to insert the image and modify its display to match the desired design.
Step 3
Replace the text view with the image of Turtle Rock by using the
Image(_:)initializer.Step 4
Add a call to
clipShape(Circle())to apply the circular clipping shape to the image.The
Circletype is a shape that you can use as a mask, or as a view by giving the circle a stroke or fill.Step 5
Create another circle with a gray stroke, and then add it as an overlay to give the image a border.
Step 6
Next, add a shadow with a 10 point radius.
Step 7
Switch the border color to white.
This completes the image view.
同时使用UIKit和SwiftUI视图-Use UIKit and SwiftUI Views Together
现在你已经准备好创建一个地图视图了。你可以使用MapKit的MKMapView类来渲染地图。
要在SwiftUI中使用UIView子类,你可以将其他视图包裹在符合UIViewRepresentable协议的SwiftUI视图中。SwiftUI包括类似的WatchKit和AppKit视图的协议。
Now you’re ready to create a map view. You can use the
MKMapViewclass from MapKit to render the map.To use
UIViewsubclasses from within SwiftUI, you wrap the other view in a SwiftUI view that conforms to theUIViewRepresentableprotocol. SwiftUI includes similar protocols for WatchKit and AppKit views.
要开始,你将创建一个新的自定义视图,可以呈现一个MKMapView。
- 第一步
选择File > New > File,选择iOS为平台,选择SwiftUI View模板,点击Next。将新文件命名为MapView.swift,点击Create。
- 第二步
为MapKit添加一个import语句,并为MapView类型声明UIViewRepresentable的一致性(conformance)。
不要担心Xcode显示的错误;你将在接下来的几个步骤中解决这个问题。
UIViewRepresentable协议有两个需求你需要添加:一个makeUIView(context:)方法创建MKMapView ,一个 updateUIView(_:context:) 方法配置并相应视图的更新。
- 第三步
用makeUIView(context: Context)方法替换 body 属性,创建并返回一个空的 MKMapView。
- 第四步
创建一个updateUIView(_:context:)方法,将地图视图的位置设置为正确的坐标,使地图以Turtle Rock为中心。
当预览处于静态模式时,只能完全渲染SwiftUI视图。因为MKMapView是一个UIView子类,所以你需要切换到实时预览来查看地图。
- 第五步
点击直播预览按钮,将预览切换到直播模式。您可能需要点击预览上方的Try Again或Resume按钮。
一会儿,你就会看到Joshua Tree国家公园的地图,也就是Turtle Rock的所在地。
//
// MapView.swift
// Landmarks
//
// Created by EchoSun on 2020/12/18.
//
import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
// 创建`MKMapView`
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
// 配置并相应视图的更新
func updateUIView(_ uiView: MKMapView, context: Context) {
let coordinate = CLLocationCoordinate2D(
latitude: 34.011286, longitude: -116.166868)
let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)
let region = MKCoordinateRegion(center: coordinate, span: span)
uiView.setRegion(region, animated: true)
}
}
struct MapView_Previews: PreviewProvider {
static var previews: some View {
MapView()
}
}
To get started, you’ll create a new custom view that can present an
MKMapView.Step 1
ChooseFile > New > File, selectiOSas the platform, select theSwiftUI Viewtemplate, and clickNext. Name the new file
MapView.swiftand clickCreate.Step 2
Add an
importstatement forMapKit, and declareUIViewRepresentableconformance for theMapViewtype.Don’t worry about the error that Xcode displays; you’ll fix that in the next few steps.
The
UIViewRepresentableprotocol has two requirements you need to add: amakeUIView(context:)method that creates anMKMapView, and anupdateUIView(_:context:)method that configures the view and responds to any changes.Step 3
Replace the
bodyproperty with amakeUIView(context:)method that creates and returns an emptyMKMapView.Step 4
Create an
updateUIView(_:context:)method that sets the map view’s region to the correct coordinates to center the map on Turtle Rock.When previews are in static mode, they only fully render SwiftUI views. Because
MKMapViewis aUIViewsubclass, you’ll need to switch to a live preview to see the map.Step 5
Click theLive Previewbutton to switch the preview to live mode. You might need to click theTry AgainorResumebutton above your preview.
In a moment, you’ll see a map of Joshua Tree National Park, home of Turtle Rock.
组成详细视图-Compose the Detail View
现在,您已经拥有了所需的所有组件——名称和地点、圆形图像以及位置的地图。
利用您迄今为止使用的工具,结合您的自定义视图,创建地标细节视图的最终设计。
You now have all of the components you need — the name and place, a circular image, and a map for the location.
With the tools you’ve used so far, combine your custom views to create the final design for the landmark detail view.
- 第一步
在项目导航中,选择ContentView.swift文件。
- 第二步
在外部嵌入一个VStack,使内部的VStack容纳三个文本视图。
- 第三步
将你的自定义MapView添加到堆栈的顶部。并使用frame(width:height:)设置MapView的大小。
当你只指定 "height "参数时,视图会自动调整为其内容的宽度。在这种情况下,"MapView "将展开以填充可用空间。
- 第四步
点击 Live Preview 按钮,可在合成视图中查看渲染的地图。
您可以在显示实时预览的同时继续编辑视图。
- 第五步
将 CircleImage 视图添加到堆栈中。
- 第六步:将
CircleImage视图添加到堆栈中。
要在地图视图的基础上叠加图像视图,需要在纵向上给图像一个-130点的偏移,并在图像视图底部给图像一个-130点的填充。
这些调整通过向上移动图像来为文字腾出空间。
- 第七步
在外层 "VStack "的底部添加一个Spacer,将内容推到屏幕顶部。
- 第八步
最后,为了让地图内容延伸到屏幕的顶部边缘,在地图视图中添加edgesIgnoringSafeArea(.top)修改器。
| 译者注 |
|---|
//
// ContentView.swift
// Landmarks
//
// Created by EchoSun on 2020/12/18.
//
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
MapView()
.edgesIgnoringSafeArea(.top)
.frame(height:300)
CircleImage()
.offset(y: -130)
.padding(.bottom, -130)
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
.padding()
Spacer()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Step 1
In the Project navigator, select the
ContentView.swiftfile.Step 2
Embed a
VStackthat holds the three text views in anotherVStack.Step 3
Add your custom
MapViewto the top of the stack. Set the size of theMapViewwithframe(width:height:).When you specify only the
heightparameter, the view automatically sizes to the width of its content. In this case,MapViewexpands to fill the available space.Step 4
Click theLive Previewbutton to see the rendered map in the composed view.
You can continue editing the view while showing a Live Preview.
Step 5
Add the
CircleImageview to the stack.Step 6
To layer the image view on top of the map view, give the image an offset of -130 points vertically, and padding of -130 points from the bottom of the view.
These adjustments make room for the text by moving the image upwards.
Step 7
Add a spacer at the bottom of the outer
VStackto push the content to the top of the screen.Step 8
Finally, to allow the map content to extend to the top edge of the screen, add the
edgesIgnoringSafeArea(.top)modifier to the map view.