#swiftui
#swiftui
Вопрос:
У меня есть кнопка внутри .contextMenu
(т. Е. Отметить как оплаченную)
Первое, что он делает, это переключает таблицу действий, чтобы выбрать способ оплаты. Сразу же следует некоторый код для добавления записи в календарь пользователей через EventKit.
Моя проблема в том, что я хочу, чтобы таблица действий возвращала результат ДО выполнения кода EventKit.
Как вы заставляете его ждать?
Свойства:
@State private var showPaymentSheet = false
@State private var paymentType = ""
var actionSheet: ActionSheet {
ActionSheet(title: Text("Payment Method"), buttons: [
.default(Text("💷 Cash")) { paymentType = "💷 Cash" },
.default(Text("💳 Bank Transfer")) { paymentType = "💳 Bank" },
.default(Text("🅿️ PayPal")) { paymentType = "🅿️ PayPal" },
.default(Text("🖋 Cheque")) { paymentType = "🖋 Cheque" },
.cancel()
])
}
Тело:
.contextMenu {
Button(action: {
**// Run This ActionSheet FIRST and get result of (paymentType) **
self.showPaymentSheet.toggle()
**// ONLY then continue with below **
let thisDay = self.selectDate.selectedDate
let eventStore = EventsRepository.shared.eventStore
let payment = EKEvent(eventStore: eventStore)
payment.calendar = event.calendar
payment.startDate = event.startDate
payment.endDate = event.endDate
payment.title = "💰(event.title!)"
payment.notes = "(event.notes!)nPaid: (Date().dateType(dateFormat: "EEE MMM dd yyyy @ HH:mm b " )) by (paymentType)"
payment.location = "(event.location!)"
do {
try eventStore.save(payment, span: .thisEvent)//i - Save Updated (event)
try EventsRepository.shared.eventStore.remove(event, span: .thisEvent)
EventsRepository.shared.loadAndUpdateEvents(selectedDate: thisDay)
} catch {
print("Failled to cancel event")
}
NotificationCenter.default.post(name: .eventsDidChange, object: nil)
}){
HStack {
Text("Mark as Paid")
.font(Font.custom("ChalkboardSE-Bold", size: 32))
Image("payment")
.renderingMode(.original)
}
}.actionSheet(isPresented: $showPaymentSheet, content: {
self.actionSheet})
}
Ответ №1:
Вы можете использовать onReceive
.
Вот простая демонстрация:
struct ContentView: View {
@State private var showPaymentSheet = false
@State private var paymentType = ""
var body: some View {
Button("Choose payment") {
self.showPaymentSheet.toggle()
}
.actionSheet(isPresented: $showPaymentSheet) {
self.actionSheet
}
.onReceive(Just(paymentType)) { // <- add here
guard !$0.isEmpty else { return }
self.someOtherFunc()
}
}
var actionSheet: ActionSheet {
...
}
func someOtherFunc() {
print(paymentType)
}
}
Тем не менее, я рекомендую перенести логику в отдельный класс и сохранить представление чистым. Также почему paymentType = ""
? Если это может быть не установлено, вам, вероятно, следует использовать nil
вместо этого. И почему вам нужно, чтобы это было наблюдаемым в первую очередь? Вы также можете создать отдельное перечисление для типов платежей.
С вышеуказанными изменениями мы можем написать обновленный пример:
enum PaymentType: String {
case cash = "💷 Cash"
case bank = "💳 Bank Transfer"
...
}
class PaymentHandler: ObservableObject {
func pay(_ paymentType: PaymentType) {
// print(paymentType.rawValue) // do something with `paymentType`
}
}
struct ContentView: View {
@ObservedObject private var vm = ViewModel()
@State private var showPaymentSheet = false
var body: some View {
Button("Choose payment") {
self.showPaymentSheet.toggle()
}
.actionSheet(isPresented: $showPaymentSheet) {
self.actionSheet
}
}
var actionSheet: ActionSheet {
ActionSheet(title: Text("Payment Method"), buttons: [
.default(Text(PaymentType.cash.rawValue)) { self.vm.pay(.cash) },
.default(Text(PaymentType.bank.rawValue)) { self.vm.pay(.bank) },
.cancel(),
])
}
}