因爲 API 變更,此文章部份內容已失效,最新完整中文教程及代碼請查看 github.com/WillieWangW…git
SwiftUI
表明將來構建 App 的方向,歡迎加羣一塊兒交流技術,解決問題。github
完成了基礎的地標詳情 view 後,咱們須要爲用戶提供查看完整地標列表,以及查看每一個地標詳情的方法。json
在本文中,咱們將會建立可顯示任何地標信息的 view ,並動態生成滾動列表,用戶能夠點按該列表以查看地標的詳細視圖。另外,咱們還將使用 Xcode 的
canvas
來顯示不一樣設備的大小,以此來微調 UI。canvas下載項目文件並按照如下步驟操做。swift
- 預計完成時間:35 分鐘
- 初始項目文件:下載
在 上一個教程 中,咱們把數據硬編碼到了全部自定義 view 中。在本文中,咱們來學習如何將數據傳遞到自定義 view 中並顯示。數組
下載初始項目並熟悉一下樣本數據。bash
1.1 在 Project navigator
中,選擇 Models
> Landmark.swift
。微信
Landmark.swift
聲明瞭一個 Landmark
結構體,用來存儲 app 須要顯示的全部地標數據,並從 landmarkData.json
導入一組地標數據。session
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])
}
}
複製代碼
Xcode的 canvas
會自動識別並顯示當前編輯器中符合 PreviewProvider
協議的任何類型。 preview provider
返回一個或多個 view ,其中包含了用來配置大小和設備的選項。
經過自定義 preview provider
的返回值,咱們可讓預覽來顯示須要的內容。
3.1 在 LandmarkRow_Previews
中,把 landmark
的參數改爲 landmarkData
數組的第二個元素。
預覽會當即從第一個元素切換到第二個元素的顯示。
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[1])
}
}
複製代碼
3.2 用 previewLayout(_:)
方法設置 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[1])
.previewLayout(.fixed(width: 300, height: 70))
}
}
複製代碼
咱們能夠在 preview provider
中使用 Group
來返回多個預覽。
3.3 把返回的 row
包裝到一個 Group
中,而且把第一個 row
添加回來。
Group
是一個組合 view 的容器。 Xcode 會在 canvas
中把 Group
的子 view 做爲分開的預覽渲染出來。
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 {
Group {
LandmarkRow(landmark: landmarkData[0])
.previewLayout(.fixed(width: 300, height: 70))
LandmarkRow(landmark: landmarkData[1])
.previewLayout(.fixed(width: 300, height: 70))
}
}
}
複製代碼
把 previewLayout(_:)
的調用移到 group
聲明的外面來精簡代碼。
一個 view 的子項會繼承 view 的上下文設置,好比這裏的預覽設置。
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 {
Group {
LandmarkRow(landmark: landmarkData[0])
LandmarkRow(landmark: landmarkData[1])
}
.previewLayout(.fixed(width: 300, height: 70))
}
}
複製代碼
在 preview provider
中編寫的代碼只會改變 Xcode 在 canvas
中的顯示。因爲 #if DEBUG
指令的存在,當 app 發佈時,編譯器會刪除這些代碼。
使用 SwiftUI
的 List
類型能夠顯示平臺特有的列表 view 。列表的元素能夠是靜態的,就像咱們建立的 stacks
的子 view 同樣;也能夠是動態生成的。甚至能夠把靜態和動態生成的 view 混合在一塊兒。
4.1 建立一個新的 SwiftUI
view,命名爲 LandmarkList.swift
。
4.2 把默認的 Text
view 換成 List
,而後傳入兩個包含頭兩個地標數據的 LandmarkRow
對象,做爲 List
的子項。
預覽會以適合 iOS 樣式的列表來顯示這兩個地標。
LandmarkList.swift
import SwiftUI
struct LandmarkList: View {
var body: some View {
List {
LandmarkRow(landmark: landmarkData[0])
LandmarkRow(landmark: landmarkData[1])
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
複製代碼
相比於給 list
指定單個元素,咱們還能夠直接從集合中生成 row
。
經過傳遞一個數據集合和一個給每一個元素提供 view 的閉包來讓 list
顯示集合的元素。 list
經過傳遞的閉包來把每一個集合中的元素轉換成子 view 。
5.1 移除現有的兩個靜態地標 row
,而後給 List
的初始化方法傳遞 landmarkData
。
list
使用 identifiable
的數據,咱們可使用如下兩個方法之一來讓數據變成 identifiable
:調用 identified(by:)
方法,使用 key path
屬性來惟一標識每一個元素,或者讓數據類型遵循 Identifiable
協議。
LandmarkList.swift
import SwiftUI
struct LandmarkList: View {
var body: some View {
List(landmarkData.identified(by: \.id)) { landmark in
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
複製代碼
5.2 在閉包中返回 LandmarkRow
,咱們就完成了自動生成內容的 list
。
這會給 landmarkData
數組中的每個元素建立一個 LandmarkRow
。
LandmarkList.swift
import SwiftUI
struct LandmarkList: View {
var body: some View {
List(landmarkData.identified(by: \.id)) { landmark in
LandmarkRow(landmark: landmark)
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
複製代碼
接下來,咱們經過給 Landmark
類型添加遵循 Identifiable
的聲明來簡化代碼。
5.3 切換到 Landmark.swift
,聲明遵循 Identifiable
協議。
當 Landmark
類型聲明瞭 Identifiable
協議須要的 id
屬性後,咱們就完成了對 Landmark
的修改。
Landmark.swift
import SwiftUI
import CoreLocation
struct Landmark: Hashable, Codable, Identifiable {
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
}
複製代碼
5.4 切回 LandmarkList
,刪除 identified(by:)
的調用。
從如今開始,咱們能夠直接使用 Landmark
元素的集合。
LandmarkList.swift
import SwiftUI
struct LandmarkList: View {
var body: some View {
List(landmarkData) { landmark in
LandmarkRow(landmark: landmark)
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
複製代碼
雖然列表已經能顯示了,可是咱們還不能經過點擊單個地標來查看地標詳情頁面。
把 list
嵌入一個 NavigationView
中,並把每一個 row
嵌套在一個 NavigationButton
中來設置到目標 view 的轉場,這樣 list
就具備了導航功能。
6.1 把自動建立地標的 list
嵌入到一個 NavigationView
中。
LandmarkList.swift
import SwiftUI
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
LandmarkRow(landmark: landmark)
}
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
複製代碼
調用 navigationBarTitle(_:)
方法來設置 list
顯示時導航欄的標題。
LandmarkList.swift
import SwiftUI
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
LandmarkRow(landmark: landmark)
}
.navigationBarTitle(Text("Landmarks"))
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
複製代碼
6.3 在 list
的閉包中,把返回的 row
包裝在一個 NavigationButton
中,並把 LandmarkDetail
view 做爲目標。
LandmarkList.swift
import SwiftUI
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
NavigationButton(destination: LandmarkDetail()) {
LandmarkRow(landmark: landmark)
}
}
.navigationBarTitle(Text("Landmarks"))
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
複製代碼
6.4 切換到實時模式後能夠直接在預覽中嘗試導航功能。單擊 Live Preview
按鈕,而後點擊地標來訪問詳情頁面。
LandmarkDetail
如今依然使用硬編碼的數據來顯示地標。像 LandmarkRow
同樣,LandmarkDetail
類型和它組合的其餘 view 都須要一個 landmark
屬性做爲它們的數據源。
在開始子 view 的內容時,咱們會把 CircleImage
、 MapView
和 LandmarkDetail
的顯示從硬編碼改成傳入的數據。
7.1 在 CircleImage.swif
中,添加存儲屬性 image
。
這是使用 SwiftUI
構建 view 時的常見模式。咱們的自定義 view 一般會爲特定視圖包裝和封裝一些 modifiers
。
CircleImage.swift
import SwiftUI
struct CircleImage: View {
var image: Image
var body: some View {
image
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 4))
.shadow(radius: 10)
}
}
struct CircleImage_Preview: PreviewProvider {
static var previews: some View {
CircleImage()
}
}
複製代碼
7.2 更新 preview provider
,傳遞一個 Turtle Rock
的圖片。
CircleImage.swift
import SwiftUI
struct CircleImage: View {
var image: Image
var body: some View {
image
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 4))
.shadow(radius: 10)
}
}
struct CircleImage_Preview: PreviewProvider {
static var previews: some View {
CircleImage(image: Image("turtlerock"))
}
}
複製代碼
7.3 在 MapView.swift
中,給 MapView
添加一個 coordinate
屬性,而後把經緯度的硬編碼換成使用這個屬性。
MapView.swift
import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
var coordinate: CLLocationCoordinate2D
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ view: MKMapView, context: Context) {
let span = MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
let region = MKCoordinateRegion(center: coordinate, span: span)
view.setRegion(region, animated: true)
}
}
struct MapView_Preview: PreviewProvider {
static var previews: some View {
MapView()
}
}
複製代碼
7.4 更新 preview provider
,傳遞數據數組中第一個地標的座標。
MapView.swift
import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
var coordinate: CLLocationCoordinate2D
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ view: MKMapView, context: Context) {
let span = MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
let region = MKCoordinateRegion(center: coordinate, span: span)
view.setRegion(region, animated: true)
}
}
struct MapView_Preview: PreviewProvider {
static var previews: some View {
MapView(coordinate: landmarkData[0].locationCoordinate)
}
}
複製代碼
7.5 在 LandmarkDetail.swift
中,給 LandmarkDetail
類型添加 landmark
屬性。
LandmarkDetail.swift
import SwiftUI
struct LandmarkDetail: View {
var landmark: Landmark
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()
}
}
複製代碼
7.6 更新 preview provider
,使用 landmarkData
中的第一個地標。
LandmarkDetail.swift
import SwiftUI
struct LandmarkDetail: View {
var landmark: Landmark
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(landmark: landmarkData[0])
}
}
複製代碼
7.7 將所需數據傳遞給咱們的自定義類型。
LandmarkDetail.swift
import SwiftUI
struct LandmarkDetail: View {
var landmark: Landmark
var body: some View {
VStack {
MapView(coordinate: landmark.locationCoordinate)
.frame(height: 300)
CircleImage(image: landmark.image(forSize: 250))
.offset(y: -130)
.padding(.bottom, -130)
VStack(alignment: .leading) {
Text(landmark.name)
.font(.title)
HStack(alignment: .top) {
Text(landmark.park)
.font(.subheadline)
Spacer()
Text(landmark.state)
.font(.subheadline)
}
}
.padding()
Spacer()
}
}
}
struct LandmarkDetail_Preview: PreviewProvider {
static var previews: some View {
LandmarkDetail(landmark: landmarkData[0])
}
}
複製代碼
7.8 最後,調用 navigationBarTitle(_:displayMode:)
方法,給導航欄添加顯示詳情 view 時的標題。
LandmarkDetail.swift
import SwiftUI
struct LandmarkDetail: View {
var landmark: Landmark
var body: some View {
VStack {
MapView(coordinate: landmark.locationCoordinate)
.frame(height: 300)
CircleImage(image: landmark.image(forSize: 250))
.offset(y: -130)
.padding(.bottom, -130)
VStack(alignment: .leading) {
Text(landmark.name)
.font(.title)
HStack(alignment: .top) {
Text(landmark.park)
.font(.subheadline)
Spacer()
Text(landmark.state)
.font(.subheadline)
}
}
.padding()
Spacer()
}
.navigationBarTitle(Text(landmark.name), displayMode: .inline)
}
}
struct LandmarkDetail_Preview: PreviewProvider {
static var previews: some View {
LandmarkDetail(landmark: landmarkData[0])
}
}
複製代碼
7.9 在 SceneDelegate.swift
中,把 app 的 rootView
改爲 LandmarkList
。
當咱們不使用預覽而是在模擬器中獨立運行 app 時,app 會以 SceneDelegate
中定義的 rootView
開始顯示。
SceneDelegate.swift
import UIKit
import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Use a UIHostingController as window root view controller
let window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = UIHostingController(rootView: LandmarkList())
self.window = window
window.makeKeyAndVisible()
}
// ...
}
複製代碼
7.10 在 LandmarkList.swift
中,給目標 LandmarkDetail
傳遞當前的地標。
LandmarkList.swift
import SwiftUI
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
NavigationButton(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
.navigationBarTitle(Text("Landmarks"))
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
複製代碼
7.11 切換到實時預覽,能夠查看從列表導航到正確的地標詳情 view 了。
接下來,咱們會在 LandmarkList_Previews
中添加代碼以在不一樣的設備尺寸上渲染列表。默認狀況下,預覽會以當前的 scheme
中設備的大小進行渲染。咱們能夠經過調用 previewDevice(_:)
方法來改變預覽設備。
8.1 首先,改變當前 list
的預覽來顯示 iPhone SE 的尺寸。
咱們能夠輸入任何 Xcode scheme
菜單中顯示的設備名稱。
LandmarkList.swift
import SwiftUI
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
NavigationButton(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
.navigationBarTitle(Text("Landmarks"))
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
.previewDevice(PreviewDevice(rawValue: "iPhone SE"))
}
}
複製代碼
8.2 在 list
預覽中用設備名稱數組做爲數據,將 LandmarkList
嵌入到 ForEach
實例中。
ForEach
以與 list
相同的方式對集合進行操做,這樣咱們就能夠在任何可使用子視圖的地方使用它,好比 stacks
, lists
,groups
等。當數據元素像這裏使用的字符串同樣是簡單的值類型時,咱們可使用 \.self
做爲標識符的 key path
。
LandmarkList.swift
import SwiftUI
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
NavigationButton(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
.navigationBarTitle(Text("Landmarks"))
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
ForEach(["iPhone SE", "iPhone XS Max"].identified(by: \.self)) { deviceName in
LandmarkList()
.previewDevice(PreviewDevice(rawValue: deviceName))
}
}
}
複製代碼
8.3 使用 previewDisplayName(_:)
方法把設備名稱做爲 labels
添加到預覽中。
LandmarkList.swift
import SwiftUI
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
NavigationButton(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
.navigationBarTitle(Text("Landmarks"))
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
ForEach(["iPhone SE", "iPhone XS Max"].identified(by: \.self)) { deviceName in
LandmarkList()
.previewDevice(PreviewDevice(rawValue: deviceName))
.previewDisplayName(deviceName)
}
}
}
複製代碼
8.4 咱們能夠在 canvas
中體驗不一樣的設備,對比它們在渲染 view
時的差別。