我有一个分段控件,我正在将其用作链接到selectedTab变量的应用程序工具栏中的选项卡。当我切换选项卡时,帐户列表会更改,但不会重置行列表。我尝试对所选对象使用initialValue,以确保将其重置为0,但这不会影响它。我尝试在init中进行打印,以确保init之后selected的值为0。每次,但仍然没有刷新foreach列表的行。
我想念什么?
import SwiftUI
import SQLite3
struct ContentView:View {
@EnvironmentObject var shared:SharedObject
var body: some View {
VStack {
if shared.selectedTab == 0 {
LedgerView(ledger: .Accounts)
} else if shared.selectedTab == 1 {
LedgerView(ledger: .Budgets)
} else if shared.selectedTab == 2 {
ReportsView()
}
}.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct LedgerView:View {
@EnvironmentObject var shared:SharedObject
let ledger:LedgerType
@State var selected:Int = 0
init(ledger:LedgerType) {
self.ledger = ledger
self._selected = State(initialValue: 0)
}
var body:some View {
HStack {
VStack(alignment: HorizontalAlignment.leading) {
ForEach(shared.accounts.filter({$0.ledger == ledger})) { account in
Text(account.name)
.background(account.id == self.selected ? Color.accentColor : Color.clear)
.onTapGesture {self.selected = account.id}
}
}
Divider()
VStack(alignment: HorizontalAlignment.leading) {
ForEach(shared.journalLines.filter({$0.accountID == selected})) { line in
Text("Line#\(line.id)")
}
}
}
}
}
struct ReportsView:View {
var body:some View {
Text("Under Construction ...")
}
}
class SharedObject:ObservableObject {
@Published var accounts:[Account] = []
@Published var journalLines:[JournalLine] = []
@Published var selectedTab:Int = 0
init() {
loadData()
}
}
enum LedgerType:Int {
case Accounts=0,Budgets=1
var name:String {
switch(self) {
case .Accounts: return "Accounts"
case .Budgets: return "Budgets"
}
}
}
struct Account:Identifiable {
var id:Int
var name:String
var ledger:LedgerType
}
struct Payee:Identifiable {
var id:Int
var name:String
}
struct Journal:Identifiable {
var id:Int
var date:Date
var payeeID:Int
var memo:String?
}
struct JournalLine:Identifiable {
var id:Int
var journalID:Int
var accountID:Int
var amount:Double
}
编辑简短的演示代码以尝试找出问题所在
import SwiftUI
struct ContentView: View {
@EnvironmentObject var shared:SharedObject
var body: some View {
VStack {
Picker(selection: $shared.selectedTab, label: Text("")) {
Text("Accounts").tag(0)
Text("Budgets").tag(1)
}.pickerStyle(SegmentedPickerStyle())
Divider()
if shared.selectedTab == 0 || shared.selectedTab == 1 {
LedgerView()
}
Spacer()
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct LedgerView:View {
@State var selected:Int = 0
init() {
self._selected = State(initialValue: 0)
print("LedgerView.init()")
}
var body:some View {
VStack(alignment: HorizontalAlignment.leading) {
Text("Selected: \(selected)")
Picker(selection: $selected, label: Text("")) {
Text("Account#1").tag(1)
Text("Account#2").tag(2)
Text("Account#3").tag(3)
}
}
}
}
class SharedObject: ObservableObject {
@Published var selectedTab:Int = 0
}
答案 0 :(得分:0)
根据您最近的评论,您需要的是@Binding而不是@State。解释一下:结构LedgerView只是在单独视图中的选择器的提取。当您调用LedgerView()时,这不会实例化新对象。它只是在该位置添加了选择器视图。因此,当您需要选择器在切换选项卡上进行重置时,需要使用绑定来重置选择器。这是工作代码。希望能帮助到你。
struct ContentView: View {
@EnvironmentObject var shared:SharedObject
@State var selected: Int = 0
var body: some View {
VStack {
Picker(selection: $shared.selectedTab, label: Text("")) {
Text("Accounts").tag(0)
Text("Budgets").tag(1)
}.pickerStyle(SegmentedPickerStyle())
Divider()
if shared.selectedTab == 0 || shared.selectedTab == 1 {
LedgerView(selected: $selected)
}
Spacer()
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onReceive(shared.$selectedTab) { newValue in
self.selected = 0
}
}
}
struct LedgerView:View {
@Binding var selected: Int
var body:some View {
VStack(alignment: HorizontalAlignment.leading) {
Text("Selected: \(selected)")
Picker(selection: $selected, label: Text("")) {
Text("Account#1").tag(1)
Text("Account#2").tag(2)
Text("Account#3").tag(3)
}
}
}
}
[较早的答案包含替代解决方案]
我已经修改了您的代码以使行有效。我添加了示例数据以使代码正常工作。我怀疑问题是否出在您的数据上。我还修改了枚举LedgerType以使其可迭代。这是工作代码。
我在代码中修改了以下内容:
已将传递的ledgerType传递给LedgerView作为真实来源
@EnvironmentObject var共享:SharedObject
添加了代码,以在切换选项卡时默认选择第一个帐户。在选项卡之间切换时,这会刷新行。请参阅.onReceive
希望这会有所帮助。如果您需要任何帮助,请告诉我。
struct ContentView:View {
@EnvironmentObject var shared: SharedObject
var body: some View {
VStack {
Picker(selection: $shared.selectedTab, label: Text("")) {
ForEach(0 ..< LedgerType.allCases.count) { index in
Text(LedgerType.allCases[index].rawValue).tag(index)
}
}
.pickerStyle(SegmentedPickerStyle())
if shared.selectedTab == 0 || shared.selectedTab == 1 {
LedgerView()
} else if shared.selectedTab == 2 {
ReportsView()
}
Spacer()
}.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct LedgerView:View {
@EnvironmentObject var shared:SharedObject
@State var selected: Int = 0
var body:some View {
HStack {
VStack(alignment: HorizontalAlignment.leading) {
ForEach(shared.accounts.filter({ $0.ledger == LedgerType.allCases[shared.selectedTab] })) { account in
Text(account.name)
.background(account.id == self.selected ? Color.accentColor : Color.clear)
.onTapGesture {self.selected = account.id}
}
}
Divider()
VStack(alignment: HorizontalAlignment.leading) {
ForEach(shared.journalLines.filter({$0.accountID == selected})) { line in
Text("Line#\(line.id)")
}
}
}
.onReceive(shared.$selectedTab) { newValue in
if let id = self.shared.getInitialAccountId(tabIndex: newValue) {
self.selected = id
}
}
}
}
struct ReportsView:View {
var body:some View {
Text("Under Construction ...")
}
}
class SharedObject:ObservableObject {
@Published var accounts:[Account] = []
@Published var journalLines:[JournalLine] = []
@Published var selectedTab:Int = 0
func getInitialAccountId(tabIndex: Int) -> Int? {
if tabIndex == 0 {
return accounts.filter({
$0.ledger == LedgerType.Accounts
}).first?.id
}
else if tabIndex == 1 {
return accounts.filter({
$0.ledger == LedgerType.Budgets
}).first?.id
}
else {
return accounts.filter({
$0.ledger == LedgerType.Reports
}).first?.id
}
}
init() {
accounts = [
Account(id: 1, name: "Sales", ledger: .Accounts),
Account(id: 2, name: "Purchase", ledger: .Accounts),
Account(id: 3, name: "Forecast", ledger: .Budgets)
]
journalLines = [
// Line for sales
JournalLine(id: 1, journalID: 10, accountID: 1, amount: 200),
JournalLine(id: 2, journalID: 20, accountID: 1, amount: 400),
// Line for purchase
JournalLine(id: 3, journalID: 30, accountID: 2, amount: 600),
JournalLine(id: 4, journalID: 40, accountID: 2, amount: 800)
]
}
}
enum LedgerType: String, CaseIterable {
case Accounts = "Accounts"
case Budgets = "Budgets"
case Reports = "Reports"
}
struct Account:Identifiable {
var id:Int
var name:String
var ledger:LedgerType
}
struct Payee:Identifiable {
var id:Int
var name:String
}
struct Journal:Identifiable {
var id:Int
var date:Date
var payeeID:Int
var memo:String?
}
struct JournalLine:Identifiable {
var id:Int
var journalID:Int
var accountID:Int
var amount:Double
}
答案 1 :(得分:-1)
shared.accounts
不存在。您从未初始化过
[...]
if shared.selectedTab == 0 {
LedgerView(ledger: .Accounts).environmentObject(SharedObject())
} else if shared.selectedTab == 1 {
LedgerView(ledger: .Budgets).environmentObject(SharedObject())
[...]
编辑:确保您的SceneDelgate也启动SharedObject
,否则它将无法在物理/模拟器设备上运行
-
编辑:运行代码并确认正在加载后,我运行了代码而未做任何更改,并且没有发现任何问题,您能否查看下面的gif并评论我的问题所在看到吗?