Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set accessibility only to annotations in map view?

I am trying to make my mapview accessible, but I have an isuue in doing so:

If I try to make the mapView accessible,by doing this:

   self.mapView.isAccessibilityElement=YES; 

Then, the map view is not read by the voice over.

If I set like this:

  self.mapView.isAccessibilityElement=NO;

Then the voice over is reading everything in the map, streets, buildings, my current location and my annotations.

I have given the accessibility label and hints to my annotations,but I havent provided any other value to the mapview.

I also tried by setting the accessibility elements for map view:

  [self.mapView setAccessibilityElements:@[self.mapView.annotations,self.mapView.userLocation]];

But still no luck.

Is there anyway to make voice over read only the annotations and neglect remaining elements like streets,buildings?

like image 381
ZeeroCool77 Avatar asked Aug 07 '15 13:08

ZeeroCool77


1 Answers

I think you're having difficulty because an MKMapView is a UIAccessibilityContainer, and so isAccessibilityElement if false by default.

You should look into making custom voice over rotors that allow the user to navigate your app by only your annotations.

This is a good approach, because it gives the user a custom, app specific way to navigate your map, while also not taking anything away from MKMapView's built in accessibility.

There are hardly any examples online that go into detail about creating custom rotors, but I just successfully created one doing exactly what you need it to do. I followed the WWDC Session 202 (begins at 24:17).

Here's my code:

func configureCustomRotors() {
  let favoritesRotor = UIAccessibilityCustomRotor(name: "Bridges") { predicate in
    let forward = (predicate.searchDirection == .next)

    // which element is currently highlighted
    let currentAnnotationView = predicate.currentItem.targetElement as? MKPinAnnotationView
    let currentAnnotation = (currentAnnotationView?.annotation as? BridgeAnnotation)

    // easy reference to all possible annotations
    let allAnnotations = self.mapView.annotations.filter { $0 is BridgeAnnotation }

    // we'll start our index either 1 less or 1 more, so we enter at either 0 or last element
    var currentIndex = forward ? -1 : allAnnotations.count

    // set our index to currentAnnotation's index if we can find it in allAnnotations
    if let currentAnnotation = currentAnnotation {
      if let index = allAnnotations.index(where: { (annotation) -> Bool in
        return (annotation.coordinate.latitude == currentAnnotation.coordinate.latitude) &&
    (annotation.coordinate.longitude == currentAnnotation.coordinate.longitude)
        }) {
          currentIndex = index
      }
    }

    // now that we have our currentIndex, here's a helper to give us the next element
    // the user is requesting
    let nextIndex = {(index:Int) -> Int in forward ? index + 1 : index - 1}

    currentIndex = nextIndex(currentIndex)

    while currentIndex >= 0 && currentIndex < allAnnotations.count {
      let requestedAnnotation = allAnnotations[currentIndex]

      // i can't stress how important it is to have animated set to false. save yourself the 10 hours i burnt, and just go with it. if you set it to true, the map starts moving to the annotation, but there's no guarantee the annotation has an associated view yet, because it could still be animating. in which case the line below this one will be nil, and you'll have a whole bunch of annotations that can't be navigated to
      self.mapView.setCenter(requestedAnnotation.coordinate, animated: false)
      if let annotationView = self.mapView.view(for: requestedAnnotation) {
        return UIAccessibilityCustomRotorItemResult(targetElement: annotationView, targetRange: nil)
      }

      currentIndex = nextIndex(currentIndex)
    }

    return nil
  }

  self.accessibilityCustomRotors = [favoritesRotor]
}
like image 174
djibouti33 Avatar answered Sep 18 '22 16:09

djibouti33