環境
- Xcode 12.0 beta 6 (12A8189n)
雖然在範例用了 Xcode 12 beta ,不過由於沒有用新的 API ,因此在 Xcode 11 也可以順利執行!
前言
在 Swift UI 裡面,要做出像是 UITableView 一樣,列出一系列的資料的時候會用像是這樣的用法:
ForEach(locations, id: \.id) { location in
Text(location.name)
}
寫出一個簡單的畫面的話就如圖:
程式碼如下:
import SwiftUI
struct ContentView: View {
let locations: [Location] = [
Location(name: "彰化"),
Location(name: "台中"),
Location(name: "南投"),
]
var body: some View {
VStack {
HStack {
Text("中部")
.font(.title)
.fontWeight(.heavy)
Spacer(minLength: 0)
}
.padding(.horizontal)
ScrollView {
VStack(spacing: 8) {
ForEach(locations, id: \.id) { location in
HStack {
Image(systemName: "mappin")
.font(.system(size: 19))
.foregroundColor(.red)
.padding()
VStack(alignment: .leading, spacing: 8) {
Text(location.name)
Text(location.id)
.font(.caption)
.foregroundColor(Color.gray)
}
Spacer(minLength: 0)
}
}
}
.padding()
}
}
}
}
Location 的定義
struct Location: Identifiable {
let id: String
let name: String
init(uuid: () -> String = { UUID().uuidString }, name: String) {
self.id = uuid()
self.name = name
}
}
回到正題
但是 ForEach 沒有像 UITableViewDelegate 的方法 tableView(_:didSelectRowAt:)
可以透過傳入的 indexPath 取得點擊到的那一行的索引,而在實務上又經常需要這個索引值,那該怎麼辦呢?
這時候就比較麻煩了,我們就必須透過 enumerated() 這個方法來產生 (index, value) 的陣列。
但是由於 enumerated()
本身的回傳型別是 EnumeratedSequence<Array<Element>>
,而這個型別無法直接餵給 ForEach , 編輯器就會開始抱怨:
Generic struct 'ForEach' requires that 'EnumeratedSequence<[Location]>' conform to 'RandomAccessCollection'
所以在傳入之前就還要再將她生成一個 Array ,傳入 id 的時候也因為結構不同而需要調整,就會變得這樣有點落落長的形式:
ForEach(Array(locations.enumerated()), id: \.element.id) { index, location in
// 省略
}
最終效果和程式碼
這裡就拿 index 來動態顯示不同的 SF Symbols :
程式碼
import SwiftUI
struct ContentView: View {
let locations: [Location] = [
Location(name: "彰化"),
Location(name: "台中"),
Location(name: "南投"),
]
var body: some View {
VStack {
HStack {
Text("中部")
.font(.title)
.fontWeight(.heavy)
Spacer(minLength: 0)
}
.padding(.horizontal)
ScrollView {
VStack(spacing: 8) {
ForEach(Array(locations.enumerated()), id: \.element.id) { index, location in
HStack {
Image(systemName: "mappin")
.font(.system(size: 19))
.foregroundColor(.red)
.padding()
VStack(alignment: .leading, spacing: 8) {
HStack {
// 為了顯示在這邊用 index
Image(systemName: "\(index).circle")
Text(location.name)
}
Text(location.id)
.font(.caption)
.foregroundColor(Color.gray)
}
Spacer(minLength: 0)
}
}
}
.padding()
}
}
}
}
struct Location: Identifiable {
let id: String
let name: String
init(uuid: () -> String = { UUID().uuidString }, name: String) {
self.id = uuid()
self.name = name
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
以上。