I'm building my first SwiftUI app and I've run into a blocker. When a user long-presses one of my cells, I want to show a confirmationdialog
with custom buttons.
Here's the code:
.confirmationDialog("", isPresented: $showLongPressMenu) {
Button {
//
} label: {
HStack {
Image(systemName: "checkmark.circle")
Text("Add completion")
}
}
Button {
//
} label: {
HStack {
Image(systemName: "note.text.badge.plus")
Text("Add Note")
}
}
Button("Cancel", role: .cancel) {}
}
This is sort-of working, here's the result:
But what I'm trying to achieve is something like this:
Any pointers would be amazing, thank you.
CodePudding user response:
Here's a quick pure SwiftUI
custom Dialog
I wrote using resultBuilder
avoiding the Divider
approach:
struct ContentView: View {
@State private var showConfirmationDialog = false
@State private var showModifierDialog = false
var body: some View {
VStack {
Button("Show Dialog") { showConfirmationDialog = true }
Button("Show ViewMod Dialog") {
withAnimation {
showModifierDialog = true
}
}
.padding()
}
.padding()
// standard confirmationDialog
.confirmationDialog("Test", isPresented: $showConfirmationDialog) {
Button { } label: {
Label("Add completion", systemImage: "checkmark.circle")
}
Button { } label: {
Label("Add Note", systemImage: "note.text.badge.plus")
}
Button("Cancel", role: .cancel) {}
}
// custom confirmationDialog with Icons, Cancel added automatically
.customConfirmDialog(isPresented: $showModifierDialog) {
Button {
// action
showModifierDialog = false
} label: {
Label("Add completion", systemImage: "checkmark.circle")
}
Divider() // unfortunately this is still necessary
Button {
// action
showModifierDialog = false
} label: {
Label("Add Note", systemImage: "note.text.badge.plus")
}
}
}
}
// *** Custom ConfirmDialog Modifier and View extension
extension View {
func customConfirmDialog<A: View>(isPresented: Binding<Bool>, @ViewBuilder actions: @escaping () -> A) -> some View {
return self.modifier(MyCustomModifier(isPresented: isPresented, actions: actions))
}
}
struct MyCustomModifier<A>: ViewModifier where A: View {
@Binding var isPresented: Bool
@ViewBuilder let actions: () -> A
func body(content: Content) -> some View {
ZStack {
content
.frame(maxWidth: .infinity, maxHeight: .infinity)
ZStack(alignment: .bottom) {
if isPresented {
Color.primary.opacity(0.2)
.ignoresSafeArea()
.onTapGesture {
isPresented = false
}
.transition(.opacity)
}
if isPresented {
VStack {
GroupBox {
actions()
.frame(maxWidth: .infinity, alignment: .leading)
}
GroupBox {
Button("Cancel", role: .cancel) {
isPresented = false
}
.bold()
.frame(maxWidth: .infinity, alignment: .center)
}
}
.font(.title3)
.padding(8)
.transition(.move(edge: .bottom))
}
}
}
.animation(.easeInOut, value: isPresented)
}
}