- Nov 6, 2024
SwiftUI: Observing Changes Using System Notifications
- DevTechie Inc
The Apple ecosystem leverages NotificationCenter to report changes at the system level. There are several types of notification events, such as when an app enters the background, when a user takes a screenshot on the device, or when there is a change in battery level. We can leverage these notifications to make important changes to our app.
Refer to the page below for full list of notifications:
NSNotificationName | Apple Developer Documentation
A structure that defines the name of a notification.developer.apple.com
Today, we will see how to use these system notifications in our own app. We will continue to build upon the example we saw in the previous article, where we built a view to pass data using NotificationCenter. If you build and run the example in the simulator and change the device orientation, you will notice that the VStack shrinks the content but keeps the layout same. What if we want to change the layout from vertical to horizontal based on the device’s orientation? There are a number of ways to do this, but this is a perfect example to show the usage of observing notifications produced at the system level.
Let’s begin by creating an enum to represent the orientations we are interested in.
enum DTOrientation {
case potrait
case landscape
}Next, we will create an observable class to monitor orientation change notifications.
import Observation
@Observable
final class SystemNotificationExample {
let center = NotificationCenter.default
var orientation = DTOrientation.potrait
init() {
Task(priority: .background) {
await orientationChangeNotification()
}
}
@MainActor
func orientationChangeNotification() async {
let name = UIDevice.orientationDidChangeNotification
for await notification in center.notifications(named: name) {
if let device = notification.object as? UIDevice {
if device.orientation.isPortrait {
orientation = .potrait
} else {
orientation = .landscape
}
}
}
}
}
extension Notification: @unchecked Sendable { }We are ready to observe the orientation changes now so let’s update the “NotificationExampleView” view.
Let’s first create State variable for “SystemNotificationExample” class so we can receive the changes in variable’s state.
struct NotificationExampleView: View {
@State private var systemNotification = SystemNotificationExample()We will create an AnyLayout variable inside the body property
struct NotificationExampleView: View {
@State private var systemNotification = SystemNotificationExample()
var body: some View {
var layout = systemNotification.orientation == .potrait ? AnyLayout(VStackLayout()) : AnyLayout(HStackLayout())Next, we will use this layout instead of using VStack.
struct NotificationExampleView: View {
@State private var systemNotification = SystemNotificationExample()
var body: some View {
let layout = systemNotification.orientation == .potrait ? AnyLayout(VStackLayout()) : AnyLayout(HStackLayout())
NavigationStack {
layout {
ReceiverView()
SenderView()
}
.navigationTitle("DevTechie.com")We can use onChange modifier to capture the changed values.
struct NotificationExampleView: View {
@State private var systemNotification = SystemNotificationExample()
var body: some View {
let layout = systemNotification.orientation == .potrait ? AnyLayout(VStackLayout()) : AnyLayout(HStackLayout())
NavigationStack {
layout {
ReceiverView()
SenderView()
}
.navigationTitle("DevTechie.com")
.onChange(of: systemNotification.orientation) { oldValue, newValue in
print(oldValue)
print(newValue)
}
}
}
}
