やりたいこと
iPad Pro 11インチとキーボードフォリオとApple Pencilを購入して、色々なアプリをキーボードで操作できることに気がつきました(遅い?)。やっぱりできるアプリはキーボードショートカットが充実しています。macOSでの経験則がそのまま活かせる訳で、どうやっているのかなと調べてみました。
仕組み
以下のUIResponderのkeyCommandsをオーバーライドします。
@interface UIResponder (UIResponderKeyCommands)
@property (nullable,nonatomic,readonly) NSArray<UIKeyCommand *> *keyCommands NS_AVAILABLE_IOS(7_0); // returns an array of UIKeyCommand objects<
@end
適当なViewControllerを用意してショートカットを登録します。
override var keyCommands: [UIKeyCommand]? {
let commands = [
// コマンド+Oが押された時の定義
UIKeyCommand(input: "O", modifierFlags: .command, action: #selector(handleShortcutCommand(command:)), discoverabilityTitle: "開く")
]
return commands
}
@objc func handleShortcutCommand(command: UIKeyCommand) {
if command.input == "O" {
print("開くコマンド実行")
}
}
ビルドしてコマンド+Oを実行するとログに開くコマンド実行と表示されました。コマンドキーを長押しすることで操作可能なショートカット一覧が表示されます。定義した開くコマンドが表示されるはずです。
要は各ViewControllerにこれらを仕込んであげることでキーボード操作が実現できます。便利便利。
もう一歩踏み込んで
例えば、あるビューからモーダルで別のビューに遷移するアプリを考えてみましょう。最初のビューからコマンド+Oでモーダルを開き、モーダルはコマンド+Wで閉じたいです。
それぞれのViewControllerに開くコマンドと閉じるコマンドを定義すれば良さそうですが、実際にやってみると、モーダル表示中にコマンドキーを長押しすると開くと閉じるが二つ出てきてしまいます。
これを回避するために、以下のようにモーダルが表示されている時はkeyCommands
でnilを返してやりましょう。
override var keyCommands: [UIKeyCommand]? {
// モーダルが表示されてたらnilを返す
if self.presentedViewController != nil {
return nil
}
let commands = [
// コマンド+Oが押された時の定義
UIKeyCommand(input: "O", modifierFlags: .command, action: #selector(handleShortcutCommand(command:)), discoverabilityTitle: "開く")
]
return commands
}
@objc func handleShortcutCommand(command: UIKeyCommand) {
if command.input == "O" {
print("開くコマンド")
}
}