SwiftUI:如何在另一个视图中更新传递的数组项
Posted
技术标签:
【中文标题】SwiftUI:如何在另一个视图中更新传递的数组项【英文标题】:SwiftUI: How to update passing array item in the other view 【发布时间】:2020-02-26 19:24:39 【问题描述】:我正在尝试使用在 Textfield 中键入的新值更新数组项,但未使用编辑值更新列表。
我的代码是:
型号:
struct WalletItem: Identifiable
let id = UUID()
var name:String
var cardNumber:String
var type:String
var cvc:String
let pin:String
var dateOfExpiry:String
模型视图:
class Wallet: ObservableObject
@Published var wallets = [
WalletItem(name: "BSB", cardNumber: "123456789", type: "master card", cvc: "1234", pin: "1234", dateOfExpiry: "2016-06-29"),
WalletItem(name: "Alpha bank", cardNumber: "123456789", type: "master card", cvc: "1234", pin: "1234", dateOfExpiry: "2017-03-12"),
WalletItem(name: "MTБ", cardNumber: "123456789", type: "master card", cvc: "1234", pin: "1234", dateOfExpiry: "2020-11-12"),
]
第一次查看:
struct WalletListView: View
// Properties
// ==========
@ObservedObject var wallet = Wallet()
@State var isNewItemSheetIsVisible = false
var body: some View
NavigationView
List(wallet.wallets) walletItem in
NavigationLink(destination: EditWalletItem(walletItem: walletItem))
Text(walletItem.name)
.navigationBarTitle("Cards", displayMode: .inline)
.navigationBarItems(
leading: Button(action: self.isNewItemSheetIsVisible = true
)
HStack
Image(systemName: "plus.circle.fill")
Text("Add item")
)
.sheet(isPresented: $isNewItemSheetIsVisible)
NewWalletItem(wallet: self.wallet)
和次要观点:
struct EditWalletItem: View
@State var walletItem: WalletItem
@Environment(\.presentationMode) var presentationMode
var body: some View
Form
Section(header: Text("Card Name"))
TextField("", text: $walletItem.name)
.navigationBarItems(leading:
Button(action:
self.presentationMode.wrappedValue.dismiss()
)
Text("Back")
, trailing:
Button(action:
self.presentationMode.wrappedValue.dismiss()
)
Text("Save")
)
P.S:如果我使用@Binding 而不是@State,我在第一个视图中会出现错误:初始化程序init(_:)
要求Binding<String>
符合StringProtocol
【问题讨论】:
【参考方案1】:这里是修改过的部分(测试并适用于 Xcode 11.2 / ios 13.2):
1) 确定过度绑定
struct EditWalletItem: View
@Binding var walletItem: WalletItem
2) 传递地点
List(Array(wallet.wallets.enumerated()), id: \.element.id) (i, walletItem) in
NavigationLink(destination: EditWalletItem(walletItem: self.$wallet.wallets[i]))
Text(walletItem.name)
【讨论】:
【参考方案2】:ForEach(Array(list.enumerated()))
只有在列表是 Array 而不是 ArraySlice 时才能正常工作,并且它具有复制列表的缺点。
更好的方法是使用.indexed()
助手:
struct IndexedCollection<Base: RandomAccessCollection>: RandomAccessCollection
typealias Index = Base.Index
typealias Element = (index: Index, element: Base.Element)
let base: Base
var startIndex: Index self.base.startIndex
var endIndex: Index self.base.endIndex
func index(after i: Index) -> Index
self.base.index(after: i)
func index(before i: Index) -> Index
self.base.index(before: i)
func index(_ i: Index, offsetBy distance: Int) -> Index
self.base.index(i, offsetBy: distance)
subscript(position: Index) -> Element
(index: position, element: self.base[position])
extension RandomAccessCollection
func indexed() -> IndexedCollection<Self>
IndexedCollection(base: self)
例子:
// SwiftUIPlayground
// https://github.com/ralfebert/SwiftUIPlayground/
import Foundation
import SwiftUI
struct Position
var id = UUID()
var count: Int
var name: String
class BookingModel: ObservableObject
@Published var positions: [Position]
init(positions: [Position] = [])
self.positions = positions
struct EditableListExample: View
@ObservedObject var bookingModel = BookingModel(
positions: [
Position(count: 1, name: "Candy"),
Position(count: 0, name: "Bread"),
]
)
var body: some View
// >>> Passing a binding into an Array via index:
List(bookingModel.positions.indexed(), id: \.element.id) i, _ in
PositionRowView(position: self.$bookingModel.positions[i])
struct PositionRowView: View
@Binding var position: Position
var body: some View
Stepper(
value: $position.count,
label:
Text("\(position.count)x \(position.name)")
)
struct EditableListExample_Previews: PreviewProvider
static var previews: some View
EditableListExample()
另见:
How does the Apple-suggested .indexed() property work in a ForEach?【讨论】:
以上是关于SwiftUI:如何在另一个视图中更新传递的数组项的主要内容,如果未能解决你的问题,请参考以下文章
如何将字符串数组从视图模型传递到 swiftUI 中播放歌曲
SwiftUI如何在更新已发布数组中的对象而不是数组本身时更新视图