03
Feb
2021
Custom View Dialog in SwiftUI
Reading time: 1 min
This recipe show how to display a custom dialog in SwiftUI. You can customize the dialog content in any way you want.
Here's what the end result can look like:
This component is available as a Swift Package in this repo.
The custom dialog will be a ViewModifier
that wraps the attached view in a ZStack
, over which it renders the semi-transparent overlay and the dialog view itself.
struct CustomDialog<DialogContent: View>: ViewModifier {
@Binding var isShowing: Bool // set this to show/hide the dialog
let dialogContent: DialogContent
init(isShowing: Binding<Bool>,
@ViewBuilder dialogContent: () -> DialogContent) {
_isShowing = isShowing
self.dialogContent = dialogContent()
}
func body(content: Content) -> some View {
// wrap the view being modified in a ZStack and render dialog on top of it
ZStack {
content
if isShowing {
// the semi-transparent overlay
Rectangle().foregroundColor(Color.black.opacity(0.6))
// the dialog content is in a ZStack to pad it from the edges
// of the screen
ZStack {
dialogContent
.background(
RoundedRectangle(cornerRadius: 8)
.foregroundColor(.white))
}.padding(40)
}
}
}
}
extension View {
func customDialog<DialogContent: View>(
isShowing: Binding<Bool>,
@ViewBuilder dialogContent: @escaping () -> DialogContent
) -> some View {
self.modifier(CustomDialog(isShowing: isShowing, dialogContent: dialogContent))
}
}
And here's how to use it:
struct DialogTest: View {
@State private var showDialog = true
var body: some View {
List(1..<6) { index in
Text("Item \(index)")
}.customDialog(isShowing: $showDialog) { // HERE
VStack {
Text("Dialog title")
.fontWeight(.bold)
Divider()
Text("Some longer description")
.padding(.bottom, 10)
Button(action: {
showDialog = false
}) {
Text("Close dialog")
.autocapitalization(.allCharacters)
.frame(minWidth: 0, maxWidth: .infinity)
.padding()
}.buttonStyle(MyButtonStyle())
}.padding()
}
}
}
Button in the example is styled as in shown in this recipe.