日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

SwiftUI之深入解析如何创建列表展示视图和列表如何导航跳转新页面

發布時間:2024/5/21 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SwiftUI之深入解析如何创建列表展示视图和列表如何导航跳转新页面 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、前言

  • 地標詳情頁視圖已經創建完成,我們需要提供一種方式讓用戶可以查看完整的地標列表,并且可以查看每一個地標的詳情。地標詳情頁視圖的創建,請參考我的博客:SwiftUI之深入解析如何創建和組合視圖。
  • 本文將分析如何創建一個可以展示任何地標信息的視圖,并動態生成一個可滾動列表,用戶可以點擊列表項去查看地標的詳細信息;優化視圖顯示時,可以使用 Xcode 畫布來渲染多個不同設備大小下的預覽視圖。

二、樣本數據

  • 自定義視圖所展示的信息都直接被寫死在代碼中,那么如將何自定義視圖傳入樣本數據進行展示:

  • 項目工程中的 Models->Landmark.swift 文件,聲明了需要在應用中展示一個地標所需要信息的結構化名稱,并通過導入 landmarkData.json 文件中的數據,生成一個地標信息數組:
import SwiftUI import CoreLocationstruct Landmark: Hashable, Codable, Identifiable {var id: Intvar name: Stringfileprivate var imageName: Stringfileprivate var coordinates: Coordinatesvar state: Stringvar park: Stringvar category: Categoryvar locationCoordinate: CLLocationCoordinate2D {CLLocationCoordinate2D(latitude: coordinates.latitude,longitude: coordinates.longitude)}enum Category: String, CaseIterable, Codable, Hashable {case featured = "Featured"case lakes = "Lakes"case rivers = "Rivers"} }extension Landmark {var image: Image {ImageStore.shared.image(name: imageName)} }struct Coordinates: Hashable, Codable {var latitude: Doublevar longitude: Double }
  • 選擇 Resources->landmarkData.json,這個樣本數據文件如下所示:

三、創建行視圖

  • 本文創建的第一個視圖就是用來顯示每個地標的行視圖,行視圖把地標的相關信息存儲在一個屬性中,一行就可以代表一個地標,稍后就會把這些行組合成為一個列表:

  • 創建一個名為 LandmarkRow.swift 的 SwiftUI 視圖;
  • 如果預覽視圖沒有出現,可以選擇菜單編輯器->畫布,打開畫布,并點擊 Resume 進行預覽,或者使用 Command+Option+Enter 快捷鍵調出畫面,再使用 Command+Option+P 快捷鍵開始預覽模式;
  • 添加 landmark 屬性做為 LandmarkRow視圖的一個存儲屬性。當添加 landmark 屬性后,預覽視圖可能會停止工作,因為 LandmarkRow 視圖初始化時需要有一個 landmark 實例,要想修復預覽視圖,需要修改 Preview Provider;
  • 在 LandmarkRow_Previews 的靜態屬性 previews 中給 LandmarkRow 初始化器中傳入 landmark 參數,這個參數使用 landmarkData 數組的第一個元素,預覽視圖當前顯示 Hello, World;

  • 在一個 HStack 中嵌入一個 Text,修改這個 Text,讓它使用 landmark 屬性的 name 字段,在 Text 視圖前面添加一個圖片視圖,在 Text 視圖后面添加 Spacer 視圖:
struct LandmarkRow: View {var landmark : Landmarkvar body: some View {HStack {landmark.image.resizable().frame(width: 50, height: 50)Text(landmark.name)Spacer()}} }struct LandmarkRow_Previews: PreviewProvider {static var previews: some View {LandmarkRow(landmark: landmarkData[0])} }
  • 效果如下:

四、自定義行預覽

  • Xcode 的畫布會自動識別當前代碼編輯器中遵循 PreviewProvider 協議的類型,并將它們渲染并展示在畫面上;一個視圖預覽提供者(preview provider)返回一個或多個視圖,這些視圖可以配置不同的大小和設備型號??梢远ㄖ茝?preview provider 中返回的視圖被渲染在何種場景下:

  • 在 LandmarkRow_Previews 中,把 landmark 參數更新為 landmarkData 數組的第二個元素,預覽視圖會立即刷新反映第二個元素的渲染情況:
struct LandmarkRow_Previews: PreviewProvider {static var previews: some View {LandmarkRow(landmark: landmarkData[1]).previewLayout(.fixed(width: 300, height: 70))} }

  • 使用 previewLayout(_😃 修改器設置一個行視圖在列表中顯示的尺寸大小,可以使用 Group 的方式,返回多個不同場景下的預覽視圖:

  • 把預覽的行視圖包裹在 Group 中,把之前的第一個行視圖也加進去,Group 是一個容器,它可以把視圖內容組織起來,Xcode 會把 Group 內的每個子視圖當作畫布內一個單獨的預覽視圖處理:

  • 為了簡化代碼,可以把 previewLayout(_😃 這個修改器應用到外層的 Group 上,Group 的每一個子視圖會繼承自己所處環境的配置,對 preivew provider 的修改只會影響預覽畫布的表現,對實際的應用不會產生影響:

五、創建地標列表

  • 使用 SwiftUI 列表類型可以展示平臺相關的列表視圖,列表的元素可以是靜態的,類似于棧內部的子視圖,也可以是動態生成的視圖,也可以混合動態和靜態的視圖:

  • 創建 SwiftUI 視圖,命名為 LandmarkList.swift,用 List 替換默認創建的 Text,并將前兩個 LandmarkRow 實例做為列表的子元素,預覽視圖中會以列表的形式展示出兩個地標:

六、創建動態列表

  • 除了單獨列出列表中的每個元素外,列表還可以從一個集合中動態的生成:

  • 創建列表時可以傳入一個集合數據和一個閉包,閉包會針對每一個數據元素返回一個視圖,這個視圖就是列表的行視圖。
  • 從列表中移除兩個靜態指定的行視圖,給列表初始化器傳入 landmarkData 數據,列表要配合可辨別的數據類型使用,想讓數據變成可辨別的數據類型有兩種方法:
    • 傳入一個 keypath 指定數據中哪一個字段用來唯一標識這個數據元素;
    • 讓數據遵循 Identifiable 協議。
  • 在閉包中返回一個 LandmarkRow 視圖,List 初始化器中指定數據集合 landmarkData 和唯一標識符keypath:.id,這樣列表就會動態生成,如下圖所示:

  • 切換到文件 Landmark.swfit,聲明 Landmark 類型遵循 Identifiable 協議,因為 Landmark 類型已經定義了 id 屬性,正好滿足 Identifiable 協議,所以不需要添加其它代碼:

  • 現在切換回文件 LandmarkList.swift,移除 keypath.id,因為 landmarkData 數據集合的元素已經遵循了 Identifiable 協議,所以在列表初始化器中可以直接使用,不需要手動標明數據的唯一標識符了:

七、設置從列表頁到詳情頁的頁面導航

  • 地標列表可以正常渲染展示,但是列表的元素點擊后沒有反應,跳轉不到地標詳情頁;現在就要給列表添加導航能力,把列表視圖嵌套到 NavigationView 視圖中,然后把列表的每一個行視圖嵌套進 NavigationLink 視圖中,就可以建立起從地標列表視圖到地標詳情頁的跳轉:

  • 把動態生成的列表視圖嵌套進一個 NavigationView 視圖中:
struct LandmarkList: View {var body: some View {NavigationView {List(landmarkData) { landmark inLandmarkRow(landmark: landmark)}}} }
  • 調用 navigationBarTitle( _: ) 修改器設置地標列表顯示時的導航條標題:

  • 在列表的閉包中,將每一個行元素包裹在 NavigationLink 中返回,并指定 ContentView 視圖為目標視圖:
struct LandmarkList: View {var body: some View {NavigationView {List(landmarkData) { landmark inNavigationLink(destination: ContentView()) {LandmarkRow(landmark: landmark)}}.navigationBarTitle(Text("Landmarks"))}} }
  • 切換到實時預覽模式下可以直接點擊地標列表的任意一行,現在就可以跳轉到地標詳情頁:


八、子視圖傳入數據

  • ContentView 視圖目前還是使用寫死的數據進行展示,與 LandmarkRow 視圖一樣,ContentView 視圖及它內部的子視圖也需要傳入 landmark 數據,并使用它來進行實際的展示。從 ContentView 的子視圖(CircleImage、MapView)開始,需要把它們都改造成為使用傳入的數據進行展示,而不是在布局代碼中寫死數據展示:

  • 在 CircleImage.swift 文件中,添加一個存儲屬性,命名為 image,這是一種在構建 SwiftUI 視圖中很常用的模式,常常會包裹或封裝一些屬性修改器:
struct CircleImage: View {var image : Imagevar body: some View {image.clipShape(Circle()).overlay(Circle().stroke(Color.white, lineWidth: 4)).shadow(radius: 10)} }
  • 更新 CirleImage 的預覽結構體,并傳入 Turtle Rock 這個圖片進行預覽:
struct CircleImage_Previews: PreviewProvider {static var previews: some View {CircleImage(image: Image("turtlerock"))} }
  • 在 MapView.swift 中添加一個 coordinate 屬性,并使用這個屬性來替換寫死的經緯度坐標:
struct MapView: UIViewRepresentable {var coordinate : CLLocationCoordinate2Dfunc makeUIView(context: Context) -> MKMapView {MKMapView(frame: .zero)}func updateUIView(_ uiView: MKMapView, context: Context) {let span = MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)let region = MKCoordinateRegion(center: coordinate, span: span)uiView.setRegion(region, animated: true)} }
  • 更新 MapView 的預覽結構體,并傳入每一個地標的經緯度數據:
struct MapView_Previews: PreviewProvider {static var previews: some View {MapView(coordinate: landmarkData[0].locationCoordinate)} }
  • 在 ContentView.swift 中添加 landmark 屬性,更新 ContentView 預覽結構體,并傳入第一個地標的數據,把對應子視圖的數據傳入:
struct ContentView: View {var landmark : Landmarkvar body: some View {VStack {MapView(coordinate: landmark.locationCoordinate).edgesIgnoringSafeArea(.top).frame(height: 300)CircleImage(image: landmark.image).offset(x: 0, 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 ContentView_Previews: PreviewProvider {static var previews: some View {ContentView(landmark: landmarkData[0])} }
  • 最后調用 navigationBarTitle(_:displayMode:) 修改器為地標詳情頁展示時在導航條上設置一個標題:

  • 在 App 入口 BuildingListsApp.swift 類中的 Main 函數中修改根視圖為 LandmarkList:
@main struct BuildingListsApp: App {var body: some Scene {WindowGroup {LandmarkList()}} }
  • 在 LandmarkList.swift 中,傳入當前行的地標數據到地標詳情頁 ContentView:
struct LandmarkList: View {var body: some View {NavigationView {List(landmarkData) { landmark inNavigationLink(destination: ContentView(landmark: landmark)) {LandmarkRow(landmark: landmark)}}.navigationBarTitle(Text("Landmarks"))}} }struct LandmarkList_Previews: PreviewProvider {static var previews: some View {LandmarkList()} }
  • 切換到實時預覽模式下去查看從地標列表頁對應的行跳轉到對應地標詳情頁是否正常:

九、動態生成預覽視圖

  • 接下來要在不同尺寸設備上展示不同的預覽視圖,默認情況下,預覽視圖會選擇當前 Scheme 選中的設備尺寸進行渲染,可以使用 previewDevice( _: ) 修改器來改變預覽視圖的設備:

  • 改變當前預覽列表,讓它渲染在 iPhone 8 Plus 設備上,可以使用 Xcode Scheme 菜單上的設備名稱來指定渲染設備:

  • 在列表的預覽視圖中,還可以把 LandmarkList 嵌套進入 ForEach 實例中,使用設備數組名作為數據。ForEach 運算作用在集合類型的數據上,就和列表使用集合類型數據一樣,可以在子視圖使用的任何場景下使用 ForEach,例如:stack、list、group 等。當元素數據是簡單值類型時(例如字符串類型),可以使用 .self 作為 keypath 去標識:
struct LandmarkList_Previews: PreviewProvider {static var previews: some View {ForEach(["iPhone 8 Plus", "iPhone 11 Pro Max"], id: \.self) { deviceName inLandmarkList().previewDevice(PreviewDevice(rawValue: deviceName))}} }
  • 使用 previewDisplayName( _: ) 修改器可以給預覽視圖添加設備標簽,可以在畫布上多設置幾個設備進行預覽,比較不同設備下視圖的展示情況。
  • 完整示例:SwiftUI之創建列表展示頁和導航跳轉詳情頁。

總結

以上是生活随笔為你收集整理的SwiftUI之深入解析如何创建列表展示视图和列表如何导航跳转新页面的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。