-
Notifications
You must be signed in to change notification settings - Fork 316
Building Lists and Navigation
完成了基础的地标详情 view 后,我们需要为用户提供查看完整地标列表,以及查看每个地标详情的方法。
在本文中,我们将会创建可显示任何地标信息的 view ,并动态生成滚动列表,用户可以点按该列表以查看地标的详细视图。另外,我们还将使用 Xcode 的
canvas
来显示不同设备的大小,以此来微调 UI。下载项目文件并按照以下步骤操作。
- 预计完成时间:35 分钟
- 初始项目文件:下载
在 上一个教程 中,我们把数据硬编码到了所有自定义 view 中。在本文中,我们来学习如何将数据传递到自定义 view 中并显示。
1.1 在 Project navigator
中,选择 Models
> Landmark.swift
。
Landmark.swift
声明了一个 Landmark
结构体,用来存储 app 需要显示的所有地标数据,并从 landmarkData.json
导入一组地标数据。
Landmark.swift
import SwiftUI
import CoreLocation
struct Landmark: Hashable, Codable {
var id: Int
var name: String
fileprivate var imageName: String
fileprivate var coordinates: Coordinates
var state: String
var park: String
var category: Category
var locationCoordinate: CLLocationCoordinate2D {
CLLocationCoordinate2D(
latitude: coordinates.latitude,
longitude: coordinates.longitude)
}
func image(forSize size: Int) -> Image {
ImageStore.shared.image(name: imageName, size: size)
}
enum Category: String, CaseIterable, Codable, Hashable {
case featured = "Featured"
case lakes = "Lakes"
case rivers = "Rivers"
}
}
struct Coordinates: Hashable, Codable {
var latitude: Double
var longitude: Double
}
1.2 在 Project navigator
中,选择 Resources
> landmarkData.json
。
我们会在本教程的剩余部分以及随后的所有内容中使用此样本数据。
landmarkData.json
[
{
"name": "Turtle Rock",
"category": "Featured",
"city": "Twentynine Palms",
"state": "California",
"id": 1001,
"park": "Joshua Tree National Park",
"coordinates": {
"longitude": -116.166868,
"latitude": 34.011286
},
"imageName": "turtlerock"
},
{
"name": "Silver Salmon Creek",
"category": "Lakes",
"city": "Port Alsworth",
"state": "Alaska",
"id": 1002,
"park": "Lake Clark National Park and Preserve",
"coordinates": {
"longitude": -152.665167,
"latitude": 59.980167
},
"imageName": "silversalmoncreek"
},
...
]
1.3 需要注意的是, 上一个教程 中的 ContentView
类型现在更名为 LandmarkDetail
。
接下来我们还会创建多个 view 类型。
LandmarkDetail.swift
import SwiftUI
struct LandmarkDetail: View {
var body: some View {
VStack {
MapView()
.frame(height: 300)
CircleImage()
.offset(y: -130)
.padding(.bottom, -130)
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack(alignment: .top) {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
.padding()
Spacer()
}
}
}
struct LandmarkDetail_Preview: PreviewProvider {
static var previews: some View {
LandmarkDetail()
}
}
我们在本文中构建的第一个 view 是用于显示每个地标详情的 row
。 row
将地标数据存储在 landmark
属性中,这样一个 row
就可以显示任何地标。稍后我们会把多个 row
组合成一个地标列表。
2.1 创建一个新的 SwiftUI
view,命名为 LandmarkRow.swift
。
2.2 如果预览没有显示,请选择 Editor
> Editor and Canvas
, 然后单击 Get Started
。
2.3 给 LandmarkRow
添加一个存储属性 landmark
。
当你添加 landmark
属性时,预览会停止工作,因为 LandmarkRow
类型在初始化时需要一个 landmark
实例。
LandmarkRow.swift
import SwiftUI
struct LandmarkRow: View {
var landmark: Landmark
var body: some View {
Text("Hello World")
}
}
struct LandmarkRow_Previews: PreviewProvider {
static var previews: some View {
LandmarkRow()
}
}
为了恢复预览,我们需要修改 PreviewProvider
。
2.4 在 LandmarkRow_Previews
的静态属性 previews
中,给 LandmarkRow
的初始化方法添加 landmark
参数,并将 landmarkData
数组的第一个元素赋值给 landmark
参数。
这时预览就会显示 Hello World
的文字。
LandmarkRow.swift
import SwiftUI
struct LandmarkRow: View {
var landmark: Landmark
var body: some View {
Text("Hello World")
}
}
struct LandmarkRow_Previews: PreviewProvider {
static var previews: some View {
LandmarkRow(landmark: landmarkData[0])
}
}
恢复预览后,我们就可以构建 row
的布局了。
2.5 把现有的 text view 嵌套到一个 HStack
中。
LandmarkRow.swift
import SwiftUI
struct LandmarkRow: View {
var landmark: Landmark
var body: some View {
HStack {
Text("Hello World")
}
}
}
struct LandmarkRow_Previews: PreviewProvider {
static var previews: some View {
LandmarkRow(landmark: landmarkData[0])
}
}
2.6 将 text view 的内容修改成 landmark.name
。
LandmarkRow.swift
import SwiftUI
struct LandmarkRow: View {
var landmark: Landmark
var body: some View {
HStack {
Text(landmark.name)
}
}
}
struct LandmarkRow_Previews: PreviewProvider {
static var previews: some View {
LandmarkRow(landmark: landmarkData[0])
}
}
2.7 在 text view 前添加一个图片来完成 row
。
LandmarkRow.swift
import SwiftUI
struct LandmarkRow: View {
var landmark: Landmark
var body: some View {
HStack {
landmark.image(forSize: 50)
Text(landmark.name)
}
}
}
struct LandmarkRow_Previews: PreviewProvider {
static var previews: some View {
LandmarkRow(landmark: landmarkData[0])
}
}
SwiftUI 纲要 - 绘制与动画 - App 设计与布局 - 框架集成