sheet 关闭后如何重新加载 ForEach 循环项
How to reload ForEach loop items after sheet is dismissed
我目前正在 sheet 视图中添加新播放器,在我关闭 sheet 视图后,主视图 ForEach 循环应该更新所有项目,但它没有。
在 ViewModel 中,我将播放器保存到 json 文件,保存后我会立即获取它。
在 sheet 视图中保存新用户名后,它会打印包含新用户名的数组,但 ForEach 循环不会在视图中更新。
如何在关闭 sheet 视图后重新加载视图?
我的主要观点:
struct PlayersView: View {
@ObservedObject var viewModel: PlayersViewModel
@State var course: Course
@State var isSelected: Bool = false
@State private var selectedItem: [Bool]
@State var selectedPlayers = [String]()
init(viewModel: PlayersViewModel, course: Course) {
self.viewModel = viewModel
self._selectedItem = State(initialValue: Array(repeating: false, count: viewModel.players.count))
self.course = course
}
var body: some View {
VStack {
ForEach(0..<viewModel.players.count) { item in
PlayerCell(isSelected: selectedItem[item], player: viewModel.players[item].playerName)
.onTapGesture {
selectedItem[item].toggle()
if selectedPlayers.contains(viewModel.players[item].playerName) {
self.selectedPlayers = selectedPlayers.filter({ [=11=] != viewModel.players[item].playerName})
} else {
selectedPlayers.append(viewModel.players[item].playerName)
}
}
}
}
我的 viewModel 看起来像这样:
class PlayersViewModel: ObservableObject {
@Published var players = [Player]()
init() {
readJSON()
}
func saveJSON(username: String) {
var array = players
array.append(Player(playerName: username))
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("example2.json")
try JSONEncoder().encode(array)
.write(to: fileURL)
readJSON()
} catch {
print(error.localizedDescription)
}
}
func readJSON() {
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("example2.json")
let data = try Data(contentsOf: fileURL)
let players = try JSONDecoder().decode([Player].self, from: data)
self.players = players
print(players)
} catch {
print(error.localizedDescription)
}
}
}
检查您的控制台,您会看到以下警告:
ForEach<Range, Int, ModifiedContent<Text, AddGestureModifier<_EndedGesture>>> count (2) != its initial count (1). ForEach(_:content:)
should only be used for constant data. Instead conform data to Identifiable
or use ForEach(_:id:content:)
and provide an explicit id
!
您可以将 0..<viewModel.players.count
替换为 viewModel.players.indices
来修复它
但如果你这样做,你将面临崩溃,因为你正在初始化 selectedItem
,当添加新项目时它没有足够的项目
您可以通过某种方式向此数组添加新的 false
,但是如果您想在开始时添加新项目,那么更新您的 [=17= 会遇到更多问题]标志数组
相反,我建议您为 Player
物品添加一个唯一标识符,并为所选玩家存储 Set
个此 ID
struct PlayersView: View {
@ObservedObject var viewModel: PlayersViewModel
@State var isSelected: Bool = false
@State private var selectedIds = Set<String>()
@State var selectedPlayers = [String]()
init(viewModel: PlayersViewModel) {
self.viewModel = viewModel
}
var body: some View {
VStack {
ForEach(viewModel.players) { player in
let selected = selectedIds.contains(player.id)
Text("\(String(describing: selected)) \(player.playerName)")
.onTapGesture {
if selected {
selectedIds.remove(player.id)
} else {
selectedIds.insert(player.id)
}
selectedPlayers = viewModel.players
.filter { selectedIds.contains([=10=].id) }
.map { [=10=].playerName }
}
}
}
}
}
struct Player: Codable, Identifiable, Hashable {
let id: String
let playerName: String
}
class PlayersViewModel: ObservableObject {
@Published var players = [Player]()
init() {
readJSON()
}
func saveJSON(username: String) {
var array = players
array.append(Player(id: UUID().uuidString, playerName: username))
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("example2.json")
try JSONEncoder().encode(array)
.write(to: fileURL)
readJSON()
} catch {
print(error.localizedDescription)
}
}
func readJSON() {
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("example2.json")
let data = try Data(contentsOf: fileURL)
let players = try JSONDecoder().decode([Player].self, from: data)
self.players = players
print(players)
} catch {
print(error.localizedDescription)
}
}
}
我目前正在 sheet 视图中添加新播放器,在我关闭 sheet 视图后,主视图 ForEach 循环应该更新所有项目,但它没有。
在 ViewModel 中,我将播放器保存到 json 文件,保存后我会立即获取它。
在 sheet 视图中保存新用户名后,它会打印包含新用户名的数组,但 ForEach 循环不会在视图中更新。
如何在关闭 sheet 视图后重新加载视图?
我的主要观点:
struct PlayersView: View {
@ObservedObject var viewModel: PlayersViewModel
@State var course: Course
@State var isSelected: Bool = false
@State private var selectedItem: [Bool]
@State var selectedPlayers = [String]()
init(viewModel: PlayersViewModel, course: Course) {
self.viewModel = viewModel
self._selectedItem = State(initialValue: Array(repeating: false, count: viewModel.players.count))
self.course = course
}
var body: some View {
VStack {
ForEach(0..<viewModel.players.count) { item in
PlayerCell(isSelected: selectedItem[item], player: viewModel.players[item].playerName)
.onTapGesture {
selectedItem[item].toggle()
if selectedPlayers.contains(viewModel.players[item].playerName) {
self.selectedPlayers = selectedPlayers.filter({ [=11=] != viewModel.players[item].playerName})
} else {
selectedPlayers.append(viewModel.players[item].playerName)
}
}
}
}
我的 viewModel 看起来像这样:
class PlayersViewModel: ObservableObject {
@Published var players = [Player]()
init() {
readJSON()
}
func saveJSON(username: String) {
var array = players
array.append(Player(playerName: username))
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("example2.json")
try JSONEncoder().encode(array)
.write(to: fileURL)
readJSON()
} catch {
print(error.localizedDescription)
}
}
func readJSON() {
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("example2.json")
let data = try Data(contentsOf: fileURL)
let players = try JSONDecoder().decode([Player].self, from: data)
self.players = players
print(players)
} catch {
print(error.localizedDescription)
}
}
}
检查您的控制台,您会看到以下警告:
ForEach<Range, Int, ModifiedContent<Text, AddGestureModifier<_EndedGesture>>> count (2) != its initial count (1).
ForEach(_:content:)
should only be used for constant data. Instead conform data toIdentifiable
or useForEach(_:id:content:)
and provide an explicitid
!
您可以将 0..<viewModel.players.count
替换为 viewModel.players.indices
来修复它
但如果你这样做,你将面临崩溃,因为你正在初始化 selectedItem
,当添加新项目时它没有足够的项目
您可以通过某种方式向此数组添加新的 false
,但是如果您想在开始时添加新项目,那么更新您的 [=17= 会遇到更多问题]标志数组
相反,我建议您为 Player
物品添加一个唯一标识符,并为所选玩家存储 Set
个此 ID
struct PlayersView: View {
@ObservedObject var viewModel: PlayersViewModel
@State var isSelected: Bool = false
@State private var selectedIds = Set<String>()
@State var selectedPlayers = [String]()
init(viewModel: PlayersViewModel) {
self.viewModel = viewModel
}
var body: some View {
VStack {
ForEach(viewModel.players) { player in
let selected = selectedIds.contains(player.id)
Text("\(String(describing: selected)) \(player.playerName)")
.onTapGesture {
if selected {
selectedIds.remove(player.id)
} else {
selectedIds.insert(player.id)
}
selectedPlayers = viewModel.players
.filter { selectedIds.contains([=10=].id) }
.map { [=10=].playerName }
}
}
}
}
}
struct Player: Codable, Identifiable, Hashable {
let id: String
let playerName: String
}
class PlayersViewModel: ObservableObject {
@Published var players = [Player]()
init() {
readJSON()
}
func saveJSON(username: String) {
var array = players
array.append(Player(id: UUID().uuidString, playerName: username))
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("example2.json")
try JSONEncoder().encode(array)
.write(to: fileURL)
readJSON()
} catch {
print(error.localizedDescription)
}
}
func readJSON() {
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("example2.json")
let data = try Data(contentsOf: fileURL)
let players = try JSONDecoder().decode([Player].self, from: data)
self.players = players
print(players)
} catch {
print(error.localizedDescription)
}
}
}