Providing feedback with the sensory feedback modifier

Providing feedback with the sensory feedback modifier

Learn how to easily add haptic feedback to your app using the sensory feedback modifier in SwiftUI

Feedback is one of the key design principles behind iOS. Receiving a visual, audio, or haptic response to the actions performed improves the user experience of an app and you can find them all around the operational system.

From unlocking the iPhone with Face ID to using toggles, menus, and all the native components, this type of feedback enriches the user experience and guides the user in understanding what's happening and the result of certain operations.

Incorporating haptic feedback into our app has never been easier using the new sensoryFeedback(trigger:_:) modifier. After the user performs an action, we can specify the type of feedback to be delivered to the user.

Implementing haptic feedback in SwiftUI

To add haptic feedback to a View component use the sensoryFeedback(_:trigger:) modifier passing two parameters:

  1. The feedback style represented by a SensoryFeedback object
  2. The trigger to perform the haptic feedback, which is a type that conforms to the Equatable protocol.

Let’s explore how we can incorporate this modifier in a simple SwiftUI View.

struct ContentView: View {

    @State private var trigger = false
    
    var body: some View {
        VStack {
            Button("Start"){
                trigger.toggle()
            }
            .sensoryFeedback(.impact, trigger: trigger)
        }
        .padding()
    }
}

In the example above a feedback of the type impact will be reproduced once the value of the property trigger is set to true.

Playing haptic feedback based on a condition

To play haptic feedback based on a specific condition of the trigger property we can include in the initializer a condition closure.

By using the sensoryFeedback(_:trigger:condition:) modifier, when the trigger value changes, the condition closure is evaluated, and the system reproduces the haptic feedback.

struct ContentView: View {
    @State private var trigger = false
    
    var body: some View {
        VStack {
            Button("Start"){
                trigger.toggle()
            }
            .sensoryFeedback(.success, trigger: trigger) { oldValue, newValue in
                return trigger == true
            }
        }
        .padding()
    }
}

Playing different haptic feedback based on the trigger property

We can also define which type of haptic feedback is going to be reproduced based on the trigger value.

In the example below, the trigger value is evaluated, and based on the evaluation a different type of feedback will be reproduced.

import SwiftUI

struct ContentView: View {
    @State private var trigger = false
    
    var body: some View {
        Button("Action") {
            trigger.toggle()
        }
        .sensoryFeedback(trigger: trigger){ old,new in
            if old == false {
                return .impact
            }
            else {
                return .error
            }
        }
    }
}

When to provide haptic feedback

SwiftUI already provides built-in types of haptic feedback that we can use inside our application. We should use it for three different purposes:

  • Indicating changes and selections: provide haptic feedback when users scroll through a menu component or change the selection of elements. Each selection should trigger a subtle haptic response, enhancing the sense of interaction.
  • Indicating the outcome of an operation: use haptic feedback to signal the success or failure of an action, similar to the feedback in the Shortcuts app when an action is successfully performed.
  • Producing a physical impact: implement haptic feedback to simulate a physical sensation, such as the feedback given when the flashlight is activated from the lock screen.

Haptic feedback for indicating selection

This type of haptic feedback can be used to indicate the successful selection of an item. For instance, you can implement haptic feedback when users switch between the light mode and dark mode of your app.

struct ContentView: View {
    @State private var colorScheme: ColorScheme = .light
    
    var body: some View {
        
        List {
            
            Button {
                colorScheme = .light
            } label: {
                HStack{
                    Text("Light mode")
                    Spacer()
                    Image(systemName: colorScheme == .light ? "checkmark" : "")
                }
            }
            
            Button {
                colorScheme = .dark
            } label: {
                HStack{
                    Text("Dark mode")
                    Spacer()
                    Image(systemName: colorScheme == .dark ? "checkmark" : "")
                }
            }
            
        }
        .sensoryFeedback(.selection, trigger: colorScheme)
        .preferredColorScheme(colorScheme)
        
    }
}

For selection purposes, we have other types of SensoryFeedback objects that include:

  • alignment: the haptic feedback we perceive when reordering a list by dragging an item.
  • decrease and increase: indicates that an important value has increased or decreased beyond a significant threshold, and is available only on Apple Watch.
  • levelChange: used to indicate a change in the level of pressure on the trackpad on MacOS.

Haptic feedback for indicating the outcome of an action

Whenever you download an app on the App Store or pay with Apple Pay you will receive specific feedback that tells you whether the action was successful or if there was an error.

We can replicate this kind of feedback using the success or error values.

import SwiftUI

struct ContentView: View {

    @State private var isActionPerformed: Bool = false
    
    var body: some View {
        
        VStack{
            Image(systemName: "swift")
                .resizable()
                .scaledToFit()
                .frame(width: 200)
                .foregroundStyle(.blue)
                .onTapGesture(count: 3) {
                    isActionPerformed.toggle()
                }
                
        }
        .sensoryFeedback(.success, trigger: isActionPerformed)
    }
}

In the example above, when the user taps three times on the image the system will reproduce a successful haptic feedback.

Haptic feedback for creating a physical impact

When activating the flashlight users will experience a unique haptic feedback designed to mimic a physical impact. This sensation is achieved by using the sensory feedback modifier and the impact feedback value.

This type of feedback is highly customizable and comes in two variants. One allows us to set the flexibility between soft, solid and rigid. The other allows us to set the weight by choosing between light, medium and heavy.

In both variants, we must set an intensity value as well.

struct ContentView: View {
    @State private var trigger = false
    
    var body: some View {
        Button("Action") {
            trigger.toggle()
        }
        .sensoryFeedback(
            .impact(weight: .heavy, intensity: 0.9),
            trigger: trigger
        )
    }
}

Conclusion

Incorporating haptic feedback into your SwiftUI applications can significantly enhance the user experience by providing tactile responses to various of their actions.

By using the sensory feedback modifier, you can easily add haptic feedback to your app's user experience, helping users better understand and enjoy their interactions with your app.

If you want an overview of all the available haptic feedback options and suggestions on how to apply the correct feedback for each action, check out the following page of the Apple's Human Interface Guidelines:

Playing haptics | Apple Developer Documentation
Playing haptics can engage people’s sense of touch and bring their familiarity with the physical world into your app or game.