SwiftUI – 显示和隐藏自定义警报

huangapple go评论70阅读模式
英文:

SwiftUI - Showing and hiding a custom alert

问题

我正在创建一个自定义警报可重用修饰符,其按钮数量取决于我需要的样式。无论如何,在下面的示例代码中,我已经尽量删除了尽可能多的额外代码,以保持其简洁和简单。

在下面的代码中,我能够显示警报,但单击“Click Me”按钮无法关闭警报。我觉得我在设置“isPresented”绑定变量时出了问题,但无法弄清楚是什么问题。我是 SwiftUI 的新手。

自定义警报修饰符:

struct CustomAlertView: ViewModifier {
    var isPresented: Binding<Bool>

    init(isPresented: Binding<Bool>) {
        self.isPresented = isPresented
    }

    func body(content: Content) -> some View {
        content.overlay(alertContent())
    }

    @ViewBuilder
    private func alertContent() -> some View {
        GeometryReader { geometry in
            if self.isPresented.wrappedValue {
                // 做一些操作

                // 单击按钮时将 isPresented 设置为 false 时没有起作用。
                Button(action: { self.isPresented.wrappedValue = false }) {
                    Text("Click Me")
                }
            }
        }
    }
}

func customAlert(isPresented: Binding<Bool>) -> some View {
    return modifier(CustomAlertView(isPresented: isPresented))
}

视图和视图模型代码:

struct MyView: View {
    @ObservedObject var viewModel: CustomViewModel = CustomViewModel()

    var body: some View {
        VStack {
            switch viewModel.state {
            case .idle:
                Color.clear.onAppear(perform: { viewModel.doSomething() })
            case .showNewView:
                // 导航
            }
        }.onAppear() {
        viewModel.state = .idle
        }.customAlert(isPresented: .constant(viewModel.showAlert))
    }
}

@MainActor
class CustomViewModel: ObservableObject {
    enum State {
        case idle
        case showNewView
    }

    @Published var state = State.idle
    @Published var showAlert = false

    func doSomething() {
        if failure {
            self.showAlert = true
        } else {
            self.state = .showNewView
        }
    }
}

我看不出你的代码有明显的错误。在你的代码中,你使用了 isPresented 绑定来显示和关闭警报。可能问题出在其他地方,比如 failure 的值。确保 failure 的值是正确的,当它为 true 时,self.showAlert 被设置为 true。如果问题仍然存在,请提供更多代码上下文以便更好地理解和解决问题。

英文:

I am creating a custom alert reusable modifier which will have different number of buttons depending upon the style I need. Anyways in my sample code below, I have removed as much extra code as I can to keep it small and simple.

With the code below, I am able to show the alert, but clicking on "Click Me" button does not dismiss the alert. I feel something is wrong with the way I am setting "isPresented" binding variable, but not able to figure out what. Am new to SwiftUI.

Custom Alert Modifier:

struct CustomAlertView: ViewModifier {
    var isPresented: Binding&lt;Bool&gt;

    init(isPresented: Binding&lt;Bool&gt;) {
        self.isPresented = isPresented
    }

    func body(content: Content) -&gt; some View {
        content.overlay(alertContent())
    }

    @ViewBuilder
    private func alertContent() -&gt; some View {
        GeometryReader { geometry in
            if self.isPresented {
                // Do something

                // Setting isPresented to false is not doing anything when button is clicked.
                Button(action: { self.isPresented.wrappedValue = false }) { 
                    Text(&quot;Click Me&quot;)
                }
            }
        }
    }
}

func customAlert(isPresented: Binding&lt;Bool&gt;) -&gt; some View {
    return modifier(CustomAlertView(isPresented: isPresented))
}

View and view model code:

struct MyView: View {
    @ObservedObject var viewModel: CustomViewModel = CustomViewModel()
    
    var body: some View {
        VStack {
            switch viewModel.state {
            case .idle:
                Color.clear.onAppear(perform: { viewModel.doSomething() })
            case .showNewView:
                // Navigate
            }
        }.onAppear() {
        viewModel.state = .idle
        }.customAlert(isPresented: .constant(viewModel.showAlert))
    }
}

@MainActor
class CustomViewModel: ObservableObject {
    enum State {
        case idle
        case showNewView
    }
    
    @Published var state = State.idle
    @Published var showAlert = false
    
    func doSomething() {
        if failure {
            self.showAlert = true
        } else {
            self.state = .showNewView
        }
    }
}

What am I doing wrong or why am I not able to dismiss the alert?

Thanks for looking!

答案1

得分: 2

首先,您需要在CustomAlertView内部使用@Binding var isPresented: Bool,并在init中将其分配为self._isPresented = isPresented

struct CustomAlertView: ViewModifier {
    @Binding var isPresented: Bool // &lt;-- 类似于这样

    init(isPresented: Binding&lt;Bool&gt;) {
        self._isPresented = isPresented // &lt;-- 以及这样
    }
//...

其次,您绝对不希望在.customAlert(isPresented: .constant(viewModel.showAlert))中将isPresented设置为常量。相反,您需要传递绑定变量:

VStack {
// ...
}
.customAlert(isPresented: $viewModel.showAlert) // &lt;-- 在这里绑定它
英文:

First of all, you want @Binding var isPresented: Bool inside the CustomAlertView, and you assign it in init as self._isPresented = isPresented:

struct CustomAlertView: ViewModifier {
    @Binding var isPresented: Bool // &lt;-- like this

    init(isPresented: Binding&lt;Bool&gt;) {
        self._isPresented = isPresented // &lt;-- and like this
    }
//...

And second, you definitely don't want to set isPresented to a constant in .customAlert(isPresented: .constant(viewModel.showAlert)). Instead, you need to pass the binding variable:

VStack {
// ...
}
.customAlert(isPresented: $viewModel.showAlert) // &lt;-- bind it here

</details>



huangapple
  • 本文由 发表于 2023年2月10日 06:24:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/75405087.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定