Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building Accessible Maps and Navigation, SwiftConf 2023

Building Accessible Maps and Navigation, SwiftConf 2023

Are you completely lost on how to make the navigation part of your application accessible? Maps and navigation can be made accessible just like any other UI component in your application. In this talk, you'll learn the best practices for how to make your maps more accessible, and what pitfalls to avoid. We'll look at existing mapping applications as examples and discuss the limits of accessibility with MapKit and Google's Maps SDK.

Robin Kanatzar

August 21, 2023
Tweet

More Decks by Robin Kanatzar

Other Decks in Technology

Transcript

  1. @@export_scripts@@ An accessible annotation... has an accessibility label is big

    enough (44 x 44 px) allows dynamic type is localized scales glyphs as well as text combines text, images, and color to show meaning has enough contrast
  2. @@export_scripts@@ UIAccessibilityCustomAction let name = "Toggle Favorite" let actionToggleFavorite =

    UIAccessibilityCustomAction(name: name) { // Do action return true|false }
  3. @@export_scripts@@ Rotor - Name let name = "Museums" let museumsRotor

    = UIAccessibilityCustomRotor(name: name) { ... }
  4. @@export_scripts@@ Rotor - Current Index let museums: [MKAnnotationView] let museumsRotor

    = UIAccessibilityCustomRotor(name: name) { predicate in let currentElement = predicate .currentItem .targetElement as? MKAnnotationView let currentIndex = museums .firstIndex { $0 == currentElement } ... }
  5. @@export_scripts@@ Rotor - Target Index ... let currentIndex = museums

    .firstIndex { $0 == currentElement } let targetIndex: Int switch predicate.searchDirection { case .previous: targetIndex = (currentIndex ?? 1) - 1 case .next: targetIndex = (currentIndex ?? -1) + 1 } guard 0..<museums.count ~= targetIndex else { return nil } ... }
  6. @@export_scripts@@ Rotor - Rotor Item Result let museums: [MKAnnotationView] let

    targetIndex: Int ... return UIAccessibilityCustomRotorItemResult( targetElement: museums[targetIndex], targetRange: nil) ...
  7. @@export_scripts@@ Rotor - All Together let museums: [MKAnnotationView] let name

    = "Museums" let museumsRotor = UIAccessibilityCustomRotor(name: name) { let currentElement = predicate .currentItem .targetElement as? MKAnnotationView let currentIndex = museums .firstIndex { $0 == currentElement } let targetIndex: Int switch predicate.searchDirection { case .previous: targetIndex = (currentIndex ?? 1) - 1 case .next: targetIndex = (currentIndex ?? -1) + 1 } guard 0..<favorites.count ~= targetIndex else { return nil } return UIAccessibilityCustomRotorItemResult( targetElement: museums[targetIndex], targetRange: nil) }
  8. @@export_scripts@@ Rotor - Map View // MapKit mkMapView.accessibilityCustomRotors = [museumsRotor]

    // Google Maps gmsMapView.accessibilityCustomRotors = [museumsRotor]
  9. @@export_scripts@@ setRegion let location = CLLocation( latitude: 48.852851, longitude: 2.349398)

    let radius = 500 // meters let region = MKCoordinateRegion( center: location.coordinate, latitudinalMeters: radius, longitudinalMeters: radius) mkMapView .setRegion(region, animated: true)
  10. @@export_scripts@@ GMSCameraPosition let camera = GMSCameraPosition .camera( withLatitude: 48.852851, longitude:

    2.349398, zoom: 16.0) let gmsMapView = GMSMapView.map( withFrame: self.view.frame, camera: camera)
  11. @@export_scripts@@ setCameraBoundary let region = MKCoordinateRegion( center: location.coordinate, latitudinalMeters: 50000,

    longitudinalMeters: 60000) let boundary = CameraBoundary(coordinateRegion: region) mkMapView.setCameraBoundary( boundary, animated: true)
  12. @@export_scripts@@ GMSMapStyle let styleURL = Bundle.main.url(forResource: "style", withExtension: "json") let

    style = GMSMapStyle( contentsOfFileURL: styleURL) gmsMapView.mapStyle = style
  13. @@export_scripts@@ Reset to Current Location // Google Maps gmsMapView.settings.myLocationButton =

    true // MapKit let currentLocation: CLLocation let region = MKCoordinateRegion( center: currentLocation.coordinate, latitudinalMeters: 500, longitudinalMeters: 500) mkMapView .setRegion(region, animated: true)
  14. @@export_scripts@@ Google Maps // Base URL https://www.google.com/maps/dir/? api=1 // Parameters

    destination=48.85840,2.29449 travelmode=driving|walking|transit
  15. @@export_scripts@@ Apple Maps MKMapItem.openInMaps(launchOptions:) // Key MKLaunchOptionsDirectionsModeKey // Values MKLaunchOptionsDirectionsModeDriving

    MKLaunchOptionsDirectionsModeWalking MKLaunchOptionsDirectionsModeTransit MKLaunchOptionsDirectionsModeDefault
  16. @@export_scripts@@ CLGeocoder let currentLocation = locationManager.requestLocation() let geocoder = CLGeocoder()

    geocoder .reverseGeocodeLocation(currentLocation) { (placemarks, error) in // placemarks: [CLPlacemark] }