开发者

Create View Function to Update Content of View

I'm not sure how to word this, please bear with me.

I am trying to create a reusable view that will serve as a confirmation dialog. The dialog will be configurable, but I'd prefer not to pollute the initializer with every possible option. Instead, I'd like to have functions/modifiers that would be used post-initialization to update the view's content.

The following is my code:

import SwiftUI

struct ConfirmationDialog: View {
    @Binding private var isPresented: Bool

    private var verb: String? = nil
    private var title: String? = nil
    private var text: String? = nil

    var confirm: () -> Void

    init(isPresented: Binding<Bool>, action confirm: @escaping () -> Void) {
        self._isPresented = isPresented
        self.confirm = confirm
    }

    public mutating func dialogVerb(_ verb: String) -> ConfirmationDialog {
        self.verb = verb
        return self
    }

    public mutating func dialogTitle(_ title: String) -> ConfirmationDialog {
        self.title = title
        return self
    }

    public mutating func dialogText(_ text: String) -> ConfirmationDialog {
        self.text = text
        return self
    }

    @Environment(\.backgroundColor) private var appBackgroundColor: Color
    @Environment(\.foregroundColor) private var appForegroundColor: Color

    var body: some View {
        OverlayView(toggle: $isPresented, backgroundColor: appBackgroundColor, cornerRadius: 0) {
            VStack(alignment: .leading) {
                if let verb = verb {
                    Text(verb)
                        .padding(top: 2, leading: 24, bottom: 2, trailing: 24)
                        .font(.callout)
                        .background(.blue)
                        .foregroundColor(.white)
                        .clipShape(RoundedRectangle(cornerRadius: 4))
                }

                if let title = title {
                    Text(title)
                        .font(.title2)
                }

                if let text = text {
                    Text(text)
                        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
                        .font(.body)
                        .fixedSize(horizontal: false, vertical: true)
                        .multilineTextAlignment(.leading)
                        .lineLimit(2)
                        .padding(bottom: 32)
                }

                ConfirmDismissView(
                    confirmTitle: "Yes",
                    dismissTitle: "No",
                    confirmAction: {
                        confirm()

                        isPresented.toggle()
                    },
                    dismissAction: { isPresented.toggle() }
                )
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
            .padding(32)
        }
    }
}

struct ConfirmationDialog_Previews: PreviewProvider {
    static var previews: some View {
        ConfirmationDialog(isPresented: .constant(true)) {}
            .dialogVerb("Action")
            .dialogTitle("Delete Task")
            .dialogText("Are you sure you want to permanently delete this task?")
    }
}

But, I get the following err开发者_高级运维or on each of my function calls:

Cannot use mutating member on immutable value: function call returns immutable value

How would I create a view function that would modify the content of my view, similar to how .navigationTitle() works?


You need to give the properties you're setting the @State attribute, which will update whatever views depend on it when changed:

@State private var verb: String? = nil
@State private var title: String? = nil
@State private var text: String? = nil

Then you don't need to make those functions mutating, since the @State vars by definition can mutate the View.

Another thing, as you mention the initializer, you can also give default values to init parameters to make them optional:

init(isPresented: Binding<Bool>,
     verb: String? = nil,
     title: String? = nil,
     text: String? = nil,
     action confirm: @escaping () -> Void) {
    self._isPresented = isPresented
    self._verb = State(initialValue: verb)
    self._title = State(initialValue: title)
    self._text = State(initialValue: text)
    self.confirm = confirm
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜