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
}
精彩评论