swiftui - @State 初始值未在 init() 上重置变量
问题描述
我有一个分段控件,我将其用作我的应用程序工具栏中的选项卡,链接到 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
}
解决方案
根据您最近的评论,您需要的是@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
}
推荐阅读
- c# - 如何创建用户类并注册新用户?
- python-3.x - 统计跨账户的EC2实例数
- xml - 谁能告诉我如何获得车道的地理坐标?
- python-3.x - 类型检查 python 列表、数组或序列仅用于数字类型
- javascript - 渲染后如何检查vue组件中的旧数据?
- reactjs - 如何在 Typescript 中将枚举值映射到它们各自的键
- react-native - Expo反应本机日志不会出现在控制台上
- wordpress - How to init public function from theme
- javascript - JavaScript CheckBox 更改颜色不起作用
- google-admin-sdk - 在 Google Admin SDK 中获取密码策略的 API