Skip to content

Instantly share code, notes, and snippets.

@danielctull
Last active April 12, 2019 07:15
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save danielctull/732ada6245d448dbb91fee22478b99e3 to your computer and use it in GitHub Desktop.
Shows selection of table view cells on pressing the up/down arrow keys.
@implementation AppDelegate
#pragma mark - Key Command Controller
- (KeyCommandController *)keyCommandController {
if (!_keyCommandController) {
UIViewController *rootViewController = self.window.rootViewController;
if (rootViewController){
_keyCommandController = [[KeyCommandController alloc] initWithRootViewController:rootViewController];
}
}
return _keyCommandController;
}
// Make the KeyCommandController part of the responder chain.
- (UIResponder *)nextResponder {
return self.keyCommandController;
}
@end
@implementation IssuesViewController
- (NSArray<UIKeyCommand *> *)keyCommands {
NSMutableArray<UIKeyCommand *> *commands = [NSMutableArray new];
[commands addObject:[UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow modifierFlags:(UIKeyModifierFlags)0 action:@selector(selectPreviousIssue:) discoverabilityTitle:@"Select Previous Issue"]];
[commands addObject:[UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow modifierFlags:(UIKeyModifierFlags)0 action:@selector(selectNextIssue:) discoverabilityTitle:@"Select Next Issue"]];
return commands;
}
- (IBAction)selectNextIssue:(id)sender {
[self selectIndexPath:self.nextIndexPath];
}
- (IBAction)selectPreviousIssue:(id)sender {
[self selectIndexPath:self.previousIndexPath];
}
- (void)selectIndexPath:(NSIndexPath *)indexPath {
if (!indexPath) return;
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionNone animated:YES];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
[self performSegueWithIdentifier:@"issue" sender:cell];
}
- (NSIndexPath *)previousIndexPath {
NSIndexPath *selectedIndexPath = self.tableView.indexPathForSelectedRow;
if (!selectedIndexPath) {
return [self lastIndexPath];
}
NSInteger selectedRow = selectedIndexPath.row;
// Loop round to the end
if (selectedRow == 0) {
return [self lastIndexPath];
}
return [NSIndexPath indexPathForRow:selectedRow - 1 inSection:0];
}
- (NSIndexPath *)nextIndexPath {
NSIndexPath *selectedIndexPath = self.tableView.indexPathForSelectedRow;
if (!selectedIndexPath) {
return [self firstIndexPath];
}
NSInteger rows = [self.tableView numberOfRowsInSection:0];
NSInteger selectedRow = selectedIndexPath.row;
// Loop round to the start
if (rows - 1 <= selectedRow) {
return [self firstIndexPath];
}
return [NSIndexPath indexPathForRow:selectedRow + 1 inSection:0];
}
@end
import UIKit
public class KeyCommandController: UIResponder {
public let rootViewController: UIViewController
public init(rootViewController: UIViewController) {
self.rootViewController = rootViewController
}
// Lets have the this become the first responder and go through all
// the view controllers and combine all their key commands. We need to make
// a note of which key commands belong to which view controller so we can
// provide the view controller in targetForAction(:withSender:) later on.
// The sender in that case is the key command, so we can just store a
// dictionary of key commands to view controllers.
var targets: [UIKeyCommand : UIViewController] = [:]
override public var keyCommands: [UIKeyCommand]? {
var commands: [UIKeyCommand] = []
var targets: [UIKeyCommand : UIViewController] = [:]
rootViewController.recurseVisibleChildViewControllers { viewController in
guard let viewControllerCommands = viewController.keyCommands else {
return
}
for command in viewControllerCommands {
commands.append(command)
targets[command] = viewController
}
}
self.targets = targets
return commands
}
override public func canBecomeFirstResponder() -> Bool {
return true
}
override public func targetForAction(action: Selector, withSender sender: AnyObject?) -> AnyObject? {
guard let command = sender as? UIKeyCommand else {
return nil
}
return targets[command]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment