簡體   English   中英

如何在SwiftUI中不使用按鈕更新@EnvironmentObject?

[英]How to update @EnvironmentObject without button in SwiftUI?

我要在這里完成的是,當filterListGraph更新數據時,iconArray將添加數量,然后也更新數據。 我試圖使用.onAppear(),但是它沒有按我預期的那樣正常工作,因為它僅在GraphView出現時才添加一次(我需要從GraphView退出並返回以更新數據)。 可以在GraphView的iconArray中添加金額然后進行更新嗎?

struct IconStruct: Identifiable {
let id = UUID()
var icon: String
var amount: Double
var color: Color
var index: Int
}

class UserSettings: ObservableObject {
@Published var iconArray: [IconStruct] = [IconStruct(icon: "FoodIcon", amount: 0, color: Color(.red), index: 0),
                                          IconStruct(icon: "ClothesIcon", amount: 0, color: Color(.blue), index: 1),
                                          IconStruct(icon: "SportIcon", amount: 0, color: Color(.yellow), index: 2)]

}

struct GraphView: View {

var dateFormatter: DateFormatter {
    let formatter = DateFormatter()
    formatter.dateStyle = .long
    return formatter
}

@EnvironmentObject var settings: UserSettings

@State private var fromDate = Calendar.current.date(byAdding: .month, value: -1, to: Date())!
@State private var toDate = Date()
@State private var selectedType = "type != %@"
@State private var selectedDate = true
@State private var searchText = ""
@State private var isNavigationBarHidden: Bool = true

var body: some View {
    ScrollView {
        VStack {

            ForEach(settings.iconArray) { row in
                Text(row.amount.description)
            }

            HStack {
                Picker("", selection: $selectedType) {
                    Text("Expense").tag("type != %@")
                    Text("Income").tag("type == %@")
                }
                .pickerStyle(SegmentedPickerStyle())

            }

            HStack {
                Picker("", selection: $selectedDate) {
                    Text("From: \(dateFormatter.string(from: fromDate))").tag(true)
                    Text("To: \(dateFormatter.string(from: toDate))").tag(false)
                }
                .pickerStyle(SegmentedPickerStyle())
            }

            DatePicker("", selection: selectedDate ? $fromDate : $toDate, displayedComponents: .date)
                .labelsHidden()
        }

        PieChartRow(data: settings.iconArray, backgroundColor: .white)
            .frame(width: 300, height: 300)

        ForEach(settings.iconArray.sorted { $0.amount > $1.amount }) { icon in
            filterListGraph(type: self.selectedType, icon: icon.icon, from: self.fromDate, to: self.toDate, iconIndex: icon.index)
        }
    }
}
}


struct filterListGraph: View {
@Environment(\.managedObjectContext) var context
var financeArray: FetchRequest<Finance>
var type: Bool
var icon: String
var iconIndex: Int

@EnvironmentObject var settings: UserSettings

var amount: Double {
    return financeArray.wrappedValue.map { $0.wrappedAmount }.reduce(0,+)
}

// var amount: Double {
// self.settings.iconArray[self.iconIndex].amount = self.financeArray.wrappedValue.map { $0.wrappedAmount }.reduce(0,+)
//    return self.settings.iconArray[self.iconIndex].amount
// }

var body: some View {
    VStack {
        if amount != 0 {
            CellContainer(image: icon, label: nil, amount: amount.description, type: type)
        }
//        .onAppear() {
//           self.settings.iconArray[self.iconIndex].amount = self.financeArray.wrappedValue.map { $0.wrappedAmount }.reduce(0,+)
//        }
    }
}

init(type: String, icon: String, from: Date, to: Date, iconIndex: Int) {
    self.iconIndex = iconIndex
    self.icon = icon
    if type == "type == %@" {
        self.type = true
    } else {
        self.type = false
    }
    financeArray = FetchRequest<Finance>(
        entity: Finance.entity(),
        sortDescriptors: [
            NSSortDescriptor(keyPath: \Finance.date, ascending: true)
        ], predicate:
        NSCompoundPredicate(notPredicateWithSubpredicate: NSCompoundPredicate.init(type: .or, subpredicates: [
            NSPredicate(format: type, "false"),
            NSPredicate(format: "icon != %@", icon),
            NSPredicate(format: "date < %@ OR date >= %@", (Calendar.current.startOfDay(for: from) as NSDate), Calendar.current.date(byAdding: .day, value: 1, to: to)! as NSDate )
        ]))
    )
}
}

如果我理解正確,則需要在UserSettings跟蹤可變數量的數組。 我無法運行您的代碼,因為有一些空格,所以這里有一些技巧,希望它們對您有所幫助。 兩者都需要使用Combine框架(您可以在此處閱讀有關內容)

  1. 嚴格在UserSettings創建可變數量 ,並在數組更改時更改它:
import Combine

class UserSettings: ObservableObject {

    @Published var amount: Double = 0.0
    @Published var iconArray: [IconStruct] {
        didSet {
            self.amount = Double(iconArray.count)
        }

    }

    init() {
        self.iconArray = [IconStruct(icon: "FoodIcon", amount: 0, color: Color(.red), index: 0),
        IconStruct(icon: "ClothesIcon", amount: 0, color: Color(.blue), index: 1),
        IconStruct(icon: "SportIcon", amount: 0, color: Color(.yellow), index: 2)]
    }

}
  1. 但是由於我不確定第一個技巧中的代碼是否足夠,您可以將AnyPublisher添加到設置中,然后對其進行訂閱:
class UserSettings: ObservableObject {

    @Published var amount: Double = 0.0
    @Published var iconArray: [IconStruct] {
        didSet {
            self.amount = Double(iconArray.count)
        }

    }

    var trackingAmount: AnyPublisher<Double, Never> {
        return $amount
            .eraseToAnyPublisher()
            // or something else you need, read about Combine
    }


    init() {
        self.iconArray = [IconStruct(icon: "FoodIcon", amount: 0, color: Color(.red), index: 0),
        IconStruct(icon: "ClothesIcon", amount: 0, color: Color(.blue), index: 1),
        IconStruct(icon: "SportIcon", amount: 0, color: Color(.yellow), index: 2)]
    }

}

// here the key idea is .onReceive(settings.trackingAmount)
struct filterListGraph: View {

    @EnvironmentObject var settings: UserSettings

    var body: some View {
        Text("some another view").onReceive(settings.trackingAmount) { _ in
            // change what you need
        }
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM