It's easy if you exploit an EnvironmentObject
to manage all of the buttons in your dashboard. Let's implement the solution step by step.
- Create an enum to define the IDs of your buttons, for example:
enum ButtonId {
case login
case signup
case forgotPassword
}
- Create a manager to keep the pressed button ID:
final class ButtonsManager: ObservableObject {
@Published var pressedButtonId: ButtonId?
}
- Create a
ButtonStyle
capable of communicate with the buttons manager. This struct will tell the manager when the button is pressed/released. In order for you to check the difference between a pressed/released/enabled/disabled button I used different colors, but it's just an example, you can customize the style as you want.
struct ButtonsManagerStyle: ButtonStyle {
@Environment(\.isEnabled) private var isEnabled: Bool
@EnvironmentObject private var buttonsManager: ButtonsManager
let buttonId: ButtonId
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding()
.foregroundColor(.white)
.contentShape(Rectangle())
.background(isEnabled ? Color.red.opacity(configuration.isPressed ? 0.3 : 1) : Color.gray.opacity(0.8))
.onChange(of: configuration.isPressed) { isPressed in
if isPressed {
buttonsManager.pressedButtonId = buttonId
} else {
buttonsManager.pressedButtonId = nil
}
}
}
}
- Create a
ViewModifier
to apply to your buttons. It will be useful in order not to replicate some logic for all of your buttons in the dashboard:
struct ButtonsManagerModifier: ViewModifier {
@EnvironmentObject private var buttonsManager: ButtonsManager
let buttonId: ButtonId
func body(content: Content) -> some View {
content
.buttonStyle(ButtonsManagerStyle(buttonId: buttonId))
.disabled(buttonsManager.pressedButtonId != nil && buttonsManager.pressedButtonId! != buttonId)
}
}
- Finally, let's use what we've implemented so far:
// MARK: - Root View
struct MyRootView: View {
@StateObject private var buttonsManager = ButtonsManager()
var body: some View {
VStack(spacing: 50) {
Button {
print("Login did tap")
} label: {
Text("Login")
}
.modifier(ButtonsManagerModifier(buttonId: .login))
SignupNestedView()
ForgotPasswordNestedView()
}
.environmentObject(buttonsManager)
}
}
// MARK: - Signup
struct SignupNestedView: View {
var body: some View {
Button {
print("Signup did tap")
} label: {
Text("Sigup")
}
.modifier(ButtonsManagerModifier(buttonId: .signup))
}
}
// MARK: - Forgot Password
struct ForgotPasswordNestedView: View {
var body: some View {
ForgotPasswordNestedNestedView()
}
}
struct ForgotPasswordNestedNestedView: View {
var body: some View {
Button {
print("Forgot password did tap")
} label: {
Text("Forgot Password")
}
.modifier(ButtonsManagerModifier(buttonId: .forgotPassword))
}
}
All you have to do is injecting the environment object in your root (whatever it is) and remember to set the modifier we've created to your buttons in the dashboard. Here's the result:
