[ios] Added accessibility labels, hints, gestures

Fixed an issue where the “return to map” accessibility element lacked a label. Always update the title and subtitle of an annotation accessibility element, in case the title or subtitle changes from one showing to the next.

Added a hint for annotations. Use declarative rather than imperative for hints.

Marked the map view and its annotations as adjustable so that swiping up and down with VoiceOver zooms out and in, respectively.

Added accessibility values to toolbar buttons in iosapp.
This commit is contained in:
Minh Nguyễn
2015-05-16 14:48:18 -07:00
parent 7cc3928a19
commit d9a2a845de
5 changed files with 100 additions and 30 deletions

View File

@@ -518,24 +518,30 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
[titleButton setTitle:styleNames[self.styleIndex] forState:UIControlStateNormal];
}
- (IBAction)locateUser:(__unused id)sender
- (IBAction)locateUser:(id)sender
{
MGLUserTrackingMode nextMode;
NSString *nextAccessibilityValue;
switch (self.mapView.userTrackingMode) {
case MGLUserTrackingModeNone:
nextMode = MGLUserTrackingModeFollow;
nextAccessibilityValue = @"Follow location";
break;
case MGLUserTrackingModeFollow:
nextMode = MGLUserTrackingModeFollowWithHeading;
nextAccessibilityValue = @"Follow location and heading";
break;
case MGLUserTrackingModeFollowWithHeading:
nextMode = MGLUserTrackingModeFollowWithCourse;
nextAccessibilityValue = @"Follow course";
break;
case MGLUserTrackingModeFollowWithCourse:
nextMode = MGLUserTrackingModeNone;
nextAccessibilityValue = @"Off";
break;
}
self.mapView.userTrackingMode = nextMode;
[sender setAccessibilityValue:nextAccessibilityValue];
}
- (IBAction)startWorldTour:(__unused id)sender

View File

@@ -38,7 +38,10 @@
</view>
<navigationItem key="navigationItem" id="p8W-eP-el5">
<nil key="title"/>
<barButtonItem key="leftBarButtonItem" image="settings.png" id="Jw8-JP-CaZ">
<barButtonItem key="leftBarButtonItem" image="settings.png" id="Jw8-JP-CaZ" userLabel="Map Settings">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityLabel" value="Map settings"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="showSettings:" destination="WaX-pd-UZQ" id="X2C-Ee-Qvt"/>
</connections>
@@ -53,12 +56,18 @@
</connections>
</button>
<rightBarButtonItems>
<barButtonItem image="TrackingLocationOffMask.png" id="CQ1-GP-M6x">
<barButtonItem image="TrackingLocationOffMask.png" id="CQ1-GP-M6x" userLabel="User Tracking Mode">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityLabel" value="User tracking mode"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="locateUser:" destination="WaX-pd-UZQ" id="XgF-DB-z3f"/>
</connections>
</barButtonItem>
<barButtonItem systemItem="organize" id="5IK-vz-jKQ">
<barButtonItem systemItem="organize" id="5IK-vz-jKQ" userLabel="Offline Packs">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityLabel" value="Offline packs"/>
</userDefinedRuntimeAttributes>
<connections>
<segue destination="7q0-lI-zqb" kind="show" identifier="ShowOfflinePacks" id="xjx-0t-0LD"/>
</connections>

View File

@@ -1,3 +1,6 @@
/* Accessibility hint */
"ANNOTATION_A11Y_HINT" = "Shows more info";
/* No comment provided by engineer. */
"API_CLIENT_400_DESC" = "The session data task failed. Original request was: %@";
@@ -29,7 +32,7 @@
"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
/* Accessibility hint */
"INFO_A11Y_HINT" = "Access credits, a feedback form, and more";
"INFO_A11Y_HINT" = "Shows credits, a feedback form, and more";
/* Accessibility label */
"INFO_A11Y_LABEL" = "About this map";

View File

@@ -133,10 +133,32 @@ mbgl::Color MGLColorObjectFromUIColor(UIColor *color)
@property (nonatomic) MGLAnnotationTag tag;
- (instancetype)initWithAccessibilityContainer:(id)container tag:(MGLAnnotationTag)identifier NS_DESIGNATED_INITIALIZER;
@end
@implementation MGLAnnotationAccessibilityElement
- (instancetype)initWithAccessibilityContainer:(id)container tag:(MGLAnnotationTag)tag
{
if (self = [super initWithAccessibilityContainer:container])
{
_tag = tag;
self.accessibilityTraits = UIAccessibilityTraitButton | UIAccessibilityTraitAdjustable;
}
return self;
}
- (void)accessibilityIncrement
{
[self.accessibilityContainer accessibilityIncrement];
}
- (void)accessibilityDecrement
{
[self.accessibilityContainer accessibilityDecrement];
}
@end
/// Lightweight container for metadata about an annotation, including the annotation itself.
@@ -160,7 +182,7 @@ public:
if (self = [super initWithAccessibilityContainer:container])
{
self.accessibilityTraits = UIAccessibilityTraitButton;
self.accessibilityLabel = self.accessibilityLabel;
self.accessibilityLabel = [self.accessibilityContainer accessibilityLabel];
self.accessibilityHint = @"Returns to the map";
}
return self;
@@ -207,7 +229,7 @@ public:
@property (nonatomic) CGFloat quickZoomStart;
@property (nonatomic, getter=isDormant) BOOL dormant;
@property (nonatomic, readonly, getter=isRotationAllowed) BOOL rotationAllowed;
@property (nonatomic) UIAccessibilityElement *mapViewProxyAccessibilityElement;
@property (nonatomic) MGLMapViewProxyAccessibilityElement *mapViewProxyAccessibilityElement;
@end
@@ -341,7 +363,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
//
// self.isAccessibilityElement = YES;
self.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"MAP_A11Y_LABEL", nil, nil, @"Map", @"Accessibility label");
self.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction;
self.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction | UIAccessibilityTraitAdjustable;
_accessibilityCompassFormatter = [[MGLCompassDirectionFormatter alloc] init];
_accessibilityCompassFormatter.unitStyle = NSFormattingUnitStyleLong;
@@ -398,7 +420,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
//
_attributionButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
_attributionButton.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"INFO_A11Y_LABEL", nil, nil, @"About this map", @"Accessibility label");
_attributionButton.accessibilityHint = NSLocalizedStringWithDefaultValue(@"INFO_A11Y_HINT", nil, nil, @"Access credits, a feedback form, and more", @"Accessibility hint");
_attributionButton.accessibilityHint = NSLocalizedStringWithDefaultValue(@"INFO_A11Y_HINT", nil, nil, @"Shows credits, a feedback form, and more", @"Accessibility hint");
[_attributionButton addTarget:self action:@selector(showAttribution) forControlEvents:UIControlEventTouchUpInside];
_attributionButton.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_attributionButton];
@@ -1922,32 +1944,30 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
NSAssert(_annotationContextsByAnnotationTag.count(annotationTag), @"Missing annotation for tag %u.", annotationTag);
MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
id <MGLAnnotation> annotation = annotationContext.annotation;
MGLAnnotationAccessibilityElement *element = annotationContext.accessibilityElement;
// Lazily create an accessibility element for the found annotation.
if ( ! element)
if ( ! annotationContext.accessibilityElement)
{
element = [[MGLAnnotationAccessibilityElement alloc] initWithAccessibilityContainer:self];
element.tag = annotationTag;
element.accessibilityTraits = UIAccessibilityTraitButton;
if ([annotation respondsToSelector:@selector(title)])
{
element.accessibilityLabel = annotation.title;
}
if ([annotation respondsToSelector:@selector(subtitle)])
{
element.accessibilityValue = annotation.subtitle;
}
annotationContext.accessibilityElement = element;
annotationContext.accessibilityElement = [[MGLAnnotationAccessibilityElement alloc] initWithAccessibilityContainer:self tag:annotationTag];
}
// Update the accessibility element’s frame.
// Update the accessibility element.
MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
CGRect annotationFrame = [self frameOfImage:annotationImage.image centeredAtCoordinate:annotation.coordinate];
CGRect screenRect = UIAccessibilityConvertFrameToScreenCoordinates(annotationFrame, self);
element.accessibilityFrame = screenRect;
annotationContext.accessibilityElement.accessibilityFrame = screenRect;
annotationContext.accessibilityElement.accessibilityHint = NSLocalizedStringWithDefaultValue(@"ANNOTATION_A11Y_HINT", nil, nil, @"Shows more info", @"Accessibility hint");
return element;
if ([annotation respondsToSelector:@selector(title)])
{
annotationContext.accessibilityElement.accessibilityLabel = annotation.title;
}
if ([annotation respondsToSelector:@selector(subtitle)])
{
annotationContext.accessibilityElement.accessibilityValue = annotation.subtitle;
}
return annotationContext.accessibilityElement;
}
- (NSInteger)indexOfAccessibilityElement:(id)element
@@ -1983,15 +2003,38 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
else return std::distance(visibleAnnotations.begin(), foundElement) + 2 /* compass, userLocationAnnotationView */;
}
- (UIAccessibilityElement *)mapViewProxyAccessibilityElement
- (MGLMapViewProxyAccessibilityElement *)mapViewProxyAccessibilityElement
{
if ( ! _mapViewProxyAccessibilityElement)
{
_mapViewProxyAccessibilityElement = [[MGLAnnotationAccessibilityElement alloc] initWithAccessibilityContainer:self];
_mapViewProxyAccessibilityElement = [[MGLMapViewProxyAccessibilityElement alloc] initWithAccessibilityContainer:self];
}
return _mapViewProxyAccessibilityElement;
}
- (void)accessibilityIncrement
{
// Swipe up to zoom out.
[self accessibilityScaleBy:0.5];
}
- (void)accessibilityDecrement
{
// Swipe down to zoom in.
[self accessibilityScaleBy:2];
}
- (void)accessibilityScaleBy:(double)scaleFactor
{
CGPoint centerPoint = self.contentCenter;
if (self.userTrackingMode != MGLUserTrackingModeNone)
{
centerPoint = self.userLocationAnnotationViewCenter;
}
_mbglMap->scaleBy(scaleFactor, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
[self unrotateIfNeededForGesture];
}
#pragma mark - Geography -
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCenterCoordinate

View File

@@ -57,8 +57,7 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
self.annotation = [[MGLUserLocation alloc] initWithMapView:mapView];
_mapView = mapView;
[self setupLayers];
self.isAccessibilityElement = YES;
self.accessibilityTraits = UIAccessibilityTraitButton;
self.accessibilityTraits = UIAccessibilityTraitButton | UIAccessibilityTraitAdjustable;
_accessibilityCoordinateFormatter = [[MGLCoordinateFormatter alloc] init];
_accessibilityCoordinateFormatter.unitStyle = NSFormattingUnitStyleLong;
@@ -108,6 +107,16 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
return [UIBezierPath bezierPathWithOvalInRect:self.frame];
}
- (void)accessibilityIncrement
{
[self.mapView accessibilityIncrement];
}
- (void)accessibilityDecrement
{
[self.mapView accessibilityDecrement];
}
- (void)setTintColor:(UIColor *)tintColor
{
if (_puckModeActivated)