Preparing your app for VoiceOver: MagicTap

Preparing your app for VoiceOver: MagicTap

Discover MagicTap and how to easily support it in both SwiftUI and UIKit.

In Preparing your App for VoiceOver: Accessibility Actions, we discussed how to execute actions within our app for users relying on assistive technology.
There are different kinds of accessibility actions available, one of them called MagicTap.

MagicTap is a useful feature for VoiceOver users that allows you to perform the primary action of a view by double-tapping with two fingers anywhere on the app screen. This feature is widely available in Apple apps. For example, while using the Phone app, you can answer and end calls, in the Clock app, you can start and stop timers, in the Music app, you can start and stop playback, and in the Camera app, you can take a picture without having to go through the app's interface.

0:00
/0:10

Using the MagicTap in the Stopwatch screen of the Clock app

Despite its utility, MagicTap is rarely implemented in third-party apps. We are going to demonstrate how to easily add MagicTap support in both SwiftUI and UIKit.

SwiftUI

In SwiftUI, implementing MagicTap is straightforward. Use the accessibilityAction(_:_:) modifier passing the .magicTap as action kind and providing a closure to handle the action.

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Hello Accessibility")
                .accessibilityAction(.magicTap){
                    print("MagicTap action performed")
                }
        }
        .padding()
    }
}

UIKit

To integrate MagicTap into your UIKit app, override the accessibilityPerformMagicTap() method within your controller class and define the desired action.

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = "Hello Accessibility"
    }
    
    override func accessibilityPerformMagicTap() -> Bool {
        print("MagicTap action performed")
        return true
    }
}
In UIKit, MagicTap functionality only works when there is a currently ‘in focus’ accessibility element within the view.

To handle Magic Tap gestures from anywhere in your app, implement the accessibilityPerformMagicTap() method in the AppDelegate.

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        return true
    }

    // MARK: UISceneSession Lifecycle
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // ...
    }


    override func accessibilityPerformMagicTap() -> Bool {
        print("MagicTap action performed")
        return true
    }
}

Conclusion

MagicTap should be used to perform the primary function of your app. This feature allows users to execute actions independently of the selected accessibility element. It is easy to implement and provides an additional accessibility option for your users.