diff --git a/README.md b/README.md index acccd4ab..f7cbee75 100644 --- a/README.md +++ b/README.md @@ -75,16 +75,19 @@ In your `tableView:cellForRowAtIndexPath:` method you set up the SWTableView cel [leftUtilityButtons sw_addUtilityButtonWithColor: [UIColor colorWithRed:0.07 green:0.75f blue:0.16f alpha:1.0] - icon:[UIImage imageNamed:@"check.png"]]; + icon:[UIImage imageNamed:@"check.png"] + accessibilityLabel:NSLocalizedString(@"Mark as done", nil)]; [leftUtilityButtons sw_addUtilityButtonWithColor: [UIColor colorWithRed:1.0f green:1.0f blue:0.35f alpha:1.0] - icon:[UIImage imageNamed:@"clock.png"]]; + icon:[UIImage imageNamed:@"clock.png"] + accessibilityLabel:NSLocalizedString(@"Schedule", nil)]; [leftUtilityButtons sw_addUtilityButtonWithColor: [UIColor colorWithRed:1.0f green:0.231f blue:0.188f alpha:1.0] icon:[UIImage imageNamed:@"cross.png"]]; [leftUtilityButtons sw_addUtilityButtonWithColor: [UIColor colorWithRed:0.55f green:0.27f blue:0.07f alpha:1.0] - icon:[UIImage imageNamed:@"list.png"]]; + icon:[UIImage imageNamed:@"list.png"] + accessibilityLabel:NSLocalizedString(@"Add to list", nil)]; return leftUtilityButtons; } diff --git a/SWTableViewCell.xcodeproj/project.pbxproj b/SWTableViewCell.xcodeproj/project.pbxproj index 50a61fb7..e75abe4a 100644 --- a/SWTableViewCell.xcodeproj/project.pbxproj +++ b/SWTableViewCell.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 6B23AE8B1AEC424000CACDB7 /* SWAccessibilityCustomAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B23AE8A1AEC424000CACDB7 /* SWAccessibilityCustomAction.m */; }; 810308911846579B00C378F0 /* NSMutableArray+SWUtilityButtons.m in Sources */ = {isa = PBXBuildFile; fileRef = 810308861846579B00C378F0 /* NSMutableArray+SWUtilityButtons.m */; }; 810308921846579B00C378F0 /* SWCellScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 810308881846579B00C378F0 /* SWCellScrollView.m */; }; 810308931846579B00C378F0 /* SWLongPressGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8103088A1846579B00C378F0 /* SWLongPressGestureRecognizer.m */; }; @@ -34,6 +35,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 6B23AE891AEC424000CACDB7 /* SWAccessibilityCustomAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SWAccessibilityCustomAction.h; sourceTree = ""; }; + 6B23AE8A1AEC424000CACDB7 /* SWAccessibilityCustomAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SWAccessibilityCustomAction.m; sourceTree = ""; }; 810308851846579B00C378F0 /* NSMutableArray+SWUtilityButtons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+SWUtilityButtons.h"; sourceTree = ""; }; 810308861846579B00C378F0 /* NSMutableArray+SWUtilityButtons.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+SWUtilityButtons.m"; sourceTree = ""; }; 810308871846579B00C378F0 /* SWCellScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SWCellScrollView.h; sourceTree = ""; }; @@ -92,6 +95,8 @@ children = ( 810308851846579B00C378F0 /* NSMutableArray+SWUtilityButtons.h */, 810308861846579B00C378F0 /* NSMutableArray+SWUtilityButtons.m */, + 6B23AE891AEC424000CACDB7 /* SWAccessibilityCustomAction.h */, + 6B23AE8A1AEC424000CACDB7 /* SWAccessibilityCustomAction.m */, 810308871846579B00C378F0 /* SWCellScrollView.h */, 810308881846579B00C378F0 /* SWCellScrollView.m */, 810308891846579B00C378F0 /* SWLongPressGestureRecognizer.h */, @@ -249,6 +254,7 @@ files = ( AF34B77517DEE2B400BD9082 /* main.m in Sources */, AF34B77917DEE2B400BD9082 /* AppDelegate.m in Sources */, + 6B23AE8B1AEC424000CACDB7 /* SWAccessibilityCustomAction.m in Sources */, 810308921846579B00C378F0 /* SWCellScrollView.m in Sources */, 810308911846579B00C378F0 /* NSMutableArray+SWUtilityButtons.m in Sources */, 810308961846579B00C378F0 /* SWUtilityButtonView.m in Sources */, diff --git a/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.h b/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.h index 87edf77c..bb2a3786 100644 --- a/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.h +++ b/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.h @@ -13,7 +13,9 @@ - (void)sw_addUtilityButtonWithColor:(UIColor *)color title:(NSString *)title; - (void)sw_addUtilityButtonWithColor:(UIColor *)color attributedTitle:(NSAttributedString *)title; - (void)sw_addUtilityButtonWithColor:(UIColor *)color icon:(UIImage *)icon; +- (void)sw_addUtilityButtonWithColor:(UIColor *)color icon:(UIImage *)icon accessibilityLabel:(NSString *)accessibilityLabel; - (void)sw_addUtilityButtonWithColor:(UIColor *)color normalIcon:(UIImage *)normalIcon selectedIcon:(UIImage *)selectedIcon; +- (void)sw_addUtilityButtonWithColor:(UIColor *)color normalIcon:(UIImage *)normalIcon selectedIcon:(UIImage *)selectedIcon accessibilityLabel:(NSString *)accessibilityLabel; @end diff --git a/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.m b/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.m index 2d32b752..70dbb9ef 100644 --- a/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.m +++ b/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.m @@ -29,23 +29,35 @@ - (void)sw_addUtilityButtonWithColor:(UIColor *)color attributedTitle:(NSAttribu [self addObject:button]; } -- (void)sw_addUtilityButtonWithColor:(UIColor *)color icon:(UIImage *)icon +- (void)sw_addUtilityButtonWithColor:(UIColor *)color icon:(UIImage *)icon accessibilityLabel:(NSString *)accessibilityLabel { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.backgroundColor = color; [button setImage:icon forState:UIControlStateNormal]; + button.accessibilityLabel = accessibilityLabel; [self addObject:button]; } -- (void)sw_addUtilityButtonWithColor:(UIColor *)color normalIcon:(UIImage *)normalIcon selectedIcon:(UIImage *)selectedIcon { +- (void)sw_addUtilityButtonWithColor:(UIColor *)color icon:(UIImage *)icon +{ + [self sw_addUtilityButtonWithColor:color icon:icon accessibilityLabel:nil]; +} + +- (void)sw_addUtilityButtonWithColor:(UIColor *)color normalIcon:(UIImage *)normalIcon selectedIcon:(UIImage *)selectedIcon accessibilityLabel:(NSString *)accessibilityLabel { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.backgroundColor = color; [button setImage:normalIcon forState:UIControlStateNormal]; [button setImage:selectedIcon forState:UIControlStateHighlighted]; [button setImage:selectedIcon forState:UIControlStateSelected]; + button.accessibilityLabel = accessibilityLabel; [self addObject:button]; } +- (void)sw_addUtilityButtonWithColor:(UIColor *)color normalIcon:(UIImage *)normalIcon selectedIcon:(UIImage *)selectedIcon +{ + [self sw_addUtilityButtonWithColor:color normalIcon:normalIcon selectedIcon:selectedIcon accessibilityLabel:nil]; +} + @end diff --git a/SWTableViewCell/PodFiles/SWAccessibilityCustomAction.h b/SWTableViewCell/PodFiles/SWAccessibilityCustomAction.h new file mode 100644 index 00000000..d8ebcc95 --- /dev/null +++ b/SWTableViewCell/PodFiles/SWAccessibilityCustomAction.h @@ -0,0 +1,18 @@ +// +// SWAccessibilityCustomAction.h +// SWTableViewCell +// +// Created by Boris Dušek on 4/25/15. +// Copyright (c) 2015 Chris Wendel. All rights reserved. +// + +#import + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 +@interface SWAccessibilityCustomAction : UIAccessibilityCustomAction + +@property(nonatomic, assign) BOOL right; +@property(nonatomic, assign) NSInteger index; + +@end +#endif diff --git a/SWTableViewCell/PodFiles/SWAccessibilityCustomAction.m b/SWTableViewCell/PodFiles/SWAccessibilityCustomAction.m new file mode 100644 index 00000000..9e78784c --- /dev/null +++ b/SWTableViewCell/PodFiles/SWAccessibilityCustomAction.m @@ -0,0 +1,15 @@ +// +// SWAccessibilityCustomAction.m +// SWTableViewCell +// +// Created by Boris Dušek (A11Y LTD.) on 4/25/15. +// Copyright (c) 2015 Chris Wendel. All rights reserved. +// + +#import "SWAccessibilityCustomAction.h" + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 +@implementation SWAccessibilityCustomAction + +@end +#endif diff --git a/SWTableViewCell/PodFiles/SWTableViewCell.m b/SWTableViewCell/PodFiles/SWTableViewCell.m index 3daceacc..9db797ea 100644 --- a/SWTableViewCell/PodFiles/SWTableViewCell.m +++ b/SWTableViewCell/PodFiles/SWTableViewCell.m @@ -8,6 +8,7 @@ #import "SWTableViewCell.h" #import "SWUtilityButtonView.h" +#import "SWAccessibilityCustomAction.h" static NSString * const kTableViewCellContentView = @"UITableViewCellContentView"; @@ -41,6 +42,12 @@ - (void)updateCellState; - (BOOL)shouldHighlight; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 +- (NSArray *)accessibilityCustomActions; +- (BOOL)_accessibilityActionActivated:(SWAccessibilityCustomAction *)action; +- (SWAccessibilityCustomAction *)_accessibilityActionForIndex:(NSInteger)index right:(BOOL)right; +#endif + @end @implementation SWTableViewCell { @@ -802,4 +809,75 @@ -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveT return ![touch.view isKindOfClass:[UIControl class]]; } +#pragma mark - UIAccessibilityAction + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 + +- (NSArray*)accessibilityCustomActions +{ + if ([UIAccessibilityCustomAction class]) + { + NSMutableArray *actions = [NSMutableArray arrayWithCapacity:_leftUtilityButtons.count + _rightUtilityButtons.count]; + + // add actions from right area first as they are usually more important + for (NSInteger index = 0; index < _rightUtilityButtons.count; ++index) + { + [actions addObject:[self _accessibilityActionForIndex:index right:YES]]; + } + + for (NSInteger index = 0; index < _leftUtilityButtons.count; ++index) + { + [actions addObject:[self _accessibilityActionForIndex:index right:NO]]; + } + + NSArray *ret = [NSArray arrayWithArray:actions]; + return ret; + } + + return @[]; +} + +- (BOOL)_accessibilityActionActivated:(SWAccessibilityCustomAction*)action +{ + if (action.right) + { + if ([self.delegate respondsToSelector:@selector(swipeableTableViewCell:didTriggerRightUtilityButtonWithIndex:)]) + { + [self.delegate swipeableTableViewCell:self didTriggerRightUtilityButtonWithIndex:action.index]; + return true; + } + } + else + { + if ([self.delegate respondsToSelector:@selector(swipeableTableViewCell:didTriggerLeftUtilityButtonWithIndex:)]) + { + [self.delegate swipeableTableViewCell:self didTriggerLeftUtilityButtonWithIndex:action.index]; + return true; + } + } + + return false; +} + +- (SWAccessibilityCustomAction *)_accessibilityActionForIndex:(NSInteger)index right:(BOOL)right +{ + NSArray *buttons = right ? [self rightUtilityButtons] : [self leftUtilityButtons]; + UIButton *button = (UIButton *)[buttons objectAtIndex:index]; + + NSString *name = button.accessibilityLabel; + if (!name) + { + // UIKit throws exception when action name is nil and it was request by accessibility support; this cannot happen for icons loaded from file as they set accessibility label to the file name without suffix; so we would be setting it to the fallback name here only in the 0.01% cases where the icon is drawn in code using e.g. Core Graphics and has no inherent name + name = NSLocalizedString(@"Unnamed action", nil); + } + + SWAccessibilityCustomAction *action = [[SWAccessibilityCustomAction alloc] initWithName:name target:self selector:@selector(_accessibilityActionActivated:)]; + action.right = right; + action.index = index; + + return action; +} + +#endif + @end diff --git a/SWTableViewCell/ViewController.m b/SWTableViewCell/ViewController.m index 3efe130e..4576ff9e 100644 --- a/SWTableViewCell/ViewController.m +++ b/SWTableViewCell/ViewController.m @@ -172,16 +172,20 @@ - (NSArray *)leftButtons [leftUtilityButtons sw_addUtilityButtonWithColor: [UIColor colorWithRed:0.07 green:0.75f blue:0.16f alpha:1.0] - icon:[UIImage imageNamed:@"check.png"]]; + icon:[UIImage imageNamed:@"check.png"] accessibilityLabel:@"Mark as done"]; + + UIImage *clockIcon = [UIImage imageNamed:@"clock.png"]; + clockIcon.accessibilityLabel = @"Schedule"; [leftUtilityButtons sw_addUtilityButtonWithColor: [UIColor colorWithRed:1.0f green:1.0f blue:0.35f alpha:1.0] - icon:[UIImage imageNamed:@"clock.png"]]; + icon:clockIcon]; + [leftUtilityButtons sw_addUtilityButtonWithColor: [UIColor colorWithRed:1.0f green:0.231f blue:0.188f alpha:1.0] icon:[UIImage imageNamed:@"cross.png"]]; [leftUtilityButtons sw_addUtilityButtonWithColor: [UIColor colorWithRed:0.55f green:0.27f blue:0.07f alpha:1.0] - icon:[UIImage imageNamed:@"list.png"]]; + icon:[UIImage imageNamed:@"list.png"] accessibilityLabel:@"Add to list"]; return leftUtilityButtons; }