管理同一个按钮的多个警报,同时避免使用已弃用的警报结构并改用实例方法

问题描述 投票:0回答:1

在 Alert 被弃用之前,我曾经通过引入 AlertState 来管理视图的不同警报:

enum AlertState: Identifiable {
    case associatedIngredient
    case confirmDelete
    
    var id: AlertState { self }
}

在我看来,我有变量

@State private var activeAlert: FoodItemViewSheets.AlertState?

我将设置 AlertState:

// Delete the food item
Button("Delete", systemImage: "trash") {
    if foodItemVM.hasAssociatedFoodItem() {
        // Check if FoodItem is related to an Ingredient
        if !foodItemVM.canBeDeleted() {
            self.activeAlert = .associatedIngredient
        } else {
            self.activeAlert = .confirmDelete
        }
    }
}

...以及之后:

.alert(item: $activeAlert) {
    alertContent($0)
}

此功能将发出正确的警报:

private func alertContent(_ state: AlertState) -> Alert {
    switch state {
    case .confirmDelete:
        return Alert(
            title: Text("Delete food"),
            message: Text("Do you really want to delete this food item? This cannot be undone!"),
            primaryButton: .default(
                Text("Do not delete")
            ),
            secondaryButton: .destructive(
                Text("Delete"),
                action: deleteFoodItemOnly
            )
        )
    case .associatedIngredient:
        return Alert(
            title: Text("Cannot delete food"),
            message: Text("This food item is in use in a recipe, please remove it from the recipe before deleting.")
        )
    }
}

不幸的是,警报已被弃用。

我想知道最好的方法是什么让这种行为(与同一按钮关联的两个不同警报)与新的alert(_:isPresented:presenting:actions:message:)实例方法一起使用。

欢迎任何想法!

swiftui alert
1个回答
0
投票

您只需要一个额外的

@State
即可传递给
isPresented:
参数。其余的都非常不言自明。您只需使用
switch
语句来提供标题、消息和操作,就像您已经在做的那样。只是你返回的是
View
,而不是
Alert

@State private var alertPresented = false
@State private var activeAlert: AlertState?

// this flag controls which alert to show in this toy example
@State private var flag = false

var body: some View {
    // as an example, I will use a toggle to control which alert to show
    Toggle("", isOn: $flag)
    Button("Delete", systemImage: "trash") {
        if flag {
            self.activeAlert = .associatedIngredient
        } else {
            self.activeAlert = .confirmDelete
        }
    }
    .alert(alertTitle, isPresented: $alertPresented, presenting: activeAlert) {
        alertActions(for: $0)
    } message: {
        alertMessage(for: $0)
    }
    .onChange(of: activeAlert) { oldValue, newValue in
        if oldValue == nil && newValue != nil {
            alertPresented = true
        } else if oldValue != nil && newValue == nil {
            alertPresented = false
        }
    }

}

@ViewBuilder
func alertMessage(for alert: AlertState) -> some View {
    switch alert {
    case .associatedIngredient:
        Text("Do you really want to delete this food item? This cannot be undone!")
    case .confirmDelete:
        Text("This food item is in use in a recipe, please remove it from the recipe before deleting.")
    }
}

@ViewBuilder
func alertActions(for alert: AlertState) -> some View {
    switch alert {
    case .associatedIngredient:
        Button("OK", role: .cancel) {}
    case .confirmDelete:
        Button("Do not delete", role: .cancel) { }
        Button("Delete", role: .destructive) {
            // ...
        }
    }
}

var alertTitle: String {
    switch activeAlert {
    case .associatedIngredient:
        "Cannot delete food"
    case .confirmDelete:
        "Delete food"
    case nil:
        ""
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.