Modular Alert In SwiftUI

Mobile Apps Academy
4 min readFeb 19, 2024

--

In this article, We will explore how to implement a Modular Custom Alert Dialog in SwiftUI

Before proceeding, please consider subscribing to our YOUTUBE CHANNEL

It gives us a lot of motivation to produce high-quality content for you guys.

if you are interested in watching the video tutorial, Check out below.

Let's start by creating the CustomAlertDialog script and add the required variables.

import SwiftUI

struct CustomAlertDialog: View {

var title: String
var message: String

var positiveButtonTitle: String? = "OK"
var negativeButtonTitle: String? = "Cancel"

private var positiveButtonAction: (() -> ())? = {}
private var negativeButtonAction: (() -> ())? = {}

private var isShowVerticalButtons = false
private let verticalButtonHeight: CGFloat = 80

init(title: String, message: String, positiveButtonTitle: String? = "OK", negativeButtonTitle: String? = "Cancel", positiveButtonAction: ( () -> Void)? = nil, negativeButtonAction: ( () -> Void)? = nil, isShowVerticalButtons: Bool = false) {
self.title = title
self.message = message
self.positiveButtonTitle = positiveButtonTitle
self.negativeButtonTitle = negativeButtonTitle
self.positiveButtonAction = positiveButtonAction
self.negativeButtonAction = negativeButtonAction
self.isShowVerticalButtons = isShowVerticalButtons
}

var body: some View {

}
}

I have added a HeaderView and a FooterView. As of now, they are just empty views which we’ll fill soon

import SwiftUI

struct CustomAlertDialog: View {

var title: String
var message: String

var positiveButtonTitle: String? = "OK"
var negativeButtonTitle: String? = "Cancel"

private var positiveButtonAction: (() -> ())? = {}
private var negativeButtonAction: (() -> ())? = {}

private var isShowVerticalButtons = false
private let verticalButtonHeight: CGFloat = 80

init(title: String, message: String, positiveButtonTitle: String? = "OK", negativeButtonTitle: String? = "Cancel", positiveButtonAction: ( () -> Void)? = nil, negativeButtonAction: ( () -> Void)? = nil, isShowVerticalButtons: Bool = false) {
self.title = title
self.message = message
self.positiveButtonTitle = positiveButtonTitle
self.negativeButtonTitle = negativeButtonTitle
self.positiveButtonAction = positiveButtonAction
self.negativeButtonAction = negativeButtonAction
self.isShowVerticalButtons = isShowVerticalButtons
}

var body: some View {
ZStack {
Color.black.opacity(0.75)
.ignoresSafeArea()

VStack(spacing: 0, content: {
HeaderView()
FooterView()
})
.frame(width: 270, height: isShowVerticalButtons ? 220 : 150)
.background(Color.white)
.cornerRadius(4)
}
.zIndex(2)
}

@ViewBuilder
private func HeaderView() -> some View {

}

@ViewBuilder
private func FooterView() -> some View {

}

}

The header view consists of a title, a message, and a divider. You can edit your dialog UI as you want.

FooterView consists of a two-button layout which will be changed to vertical or horizontal based on the boolean modifier.


@ViewBuilder
private func HeaderView() -> some View {
Text(title)
.font(.system(size: 16, weight: .bold))
.foregroundColor(.black)
.multilineTextAlignment(.center)
.frame(height: 25)
.padding(.top, 16)
.padding(.bottom, 8)
.padding(.horizontal, 16)

Text(message)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.font(.system(size: 14))
.foregroundColor(.black)
.multilineTextAlignment(.center)
.padding(.horizontal, 16)
.padding(.bottom, 16)
.minimumScaleFactor(0.5)

Divider()
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 0.5)
.padding(.all, 0)
}

@ViewBuilder
private func FooterView() -> some View {
let buttonLayout = isShowVerticalButtons ? AnyLayout(VStackLayout()) : AnyLayout(HStackLayout())
buttonLayout {
if isShowVerticalButtons {
Spacer()
}

Button(action: {
negativeButtonAction?()
}, label: {
Text(negativeButtonTitle ?? "")
.font(.system(size: 16, weight: .bold))
.foregroundColor(.black)
.multilineTextAlignment(.center)
.padding()
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
})

if isShowVerticalButtons {
Spacer()
Divider()
Spacer()
} else {
Divider()
.frame(minWidth: 0, maxWidth: 0.5, minHeight: 0, maxHeight: .infinity)
}

Button {
positiveButtonAction?()
} label: {
Text(positiveButtonTitle ?? "")
.font(.system(size: 16, weight: .bold))
.foregroundColor(.pink)
.multilineTextAlignment(.center)
.padding(15)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}

if isShowVerticalButtons {
Spacer()
}

}.padding([.horizontal, .bottom], 0)

}

We’ll use the below code to create custom modifiers.

extension CustomAlertDialog {
func makeButtonsVertical(_ isVertical: Bool) -> Self {
var alert = self
alert.isShowVerticalButtons = isVertical
return alert
}

func onPositiveButtonTap(_ positiveButtonAction: (() -> ())?) -> Self {
var alert = self
alert.positiveButtonAction = positiveButtonAction
return alert
}

func onNegativeButtonTap(_ negativeButtonAction: (() -> ())?) -> Self {
var alert = self
alert.negativeButtonAction = negativeButtonAction
return alert
}
}

Below is an example of the View

CustomAlertDialog(title: "Error", message: "Something went wrong, Please try again later..", positiveButtonTitle: "OK", negativeButtonTitle: "Cancel")
.makeButtonsVertical(false)
.onNegativeButtonTap {
presentAlert.toggle()
}
.onPositiveButtonTap {
presentAlert.toggle()
}

That's it you should be able to see the dialog now

Once again Thanks for stopping by.
Do check out our YOUTUBE CHANNEL

Social Handles

Instagram : https://www.instagram.com/mobileappsacademy/

Twitter : https://twitter.com/MobileAppsAcdmy

LinkedIn : https://www.linkedin.com/company/mobile-apps-academy/

--

--

Mobile Apps Academy

Welcome to Mobile Apps Academy, your go-to channel for all things mobile app development!