[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:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user