问题
If a key command is registered, it's action might be called many times if the user holds down the key too long. This can create very weird effects, like ⌘N could repeatedly open a new view many times. Is there any easy way to stop this behavior without resorting to something like a boolean "already triggered" flag?
Here's how I register two different key commands:
#pragma mark - KeyCommands
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (NSArray<UIKeyCommand *>*)keyCommands {
return @[
[UIKeyCommand keyCommandWithInput:@"O" modifierFlags:UIKeyModifierCommand action:@selector(keyboardShowOtherView:) discoverabilityTitle:@"Show Other View"],
[UIKeyCommand keyCommandWithInput:@"S" modifierFlags:UIKeyModifierCommand action:@selector(keyboardPlaySound:) discoverabilityTitle:@"Play Sound"],
];
}
- (void)keyboardShowOtherView:(UIKeyCommand *)sender {
NSLog(@"keyboardShowOtherView");
[self performSegueWithIdentifier:@"showOtherView" sender:nil];
}
- (void)keyboardPlaySound:(UIKeyCommand *)sender {
NSLog(@"keyboardPlaySound");
[self playSound:sender];
}
#pragma mark - Actions
- (IBAction)playSound:(id)sender {
AudioServicesPlaySystemSound(1006); // Not allowed in the AppStore
}
A sample project can be downloaded here: TestKeyCommands.zip
回答1:
In general, you don't need to deal with this, since the new view would usually become the firstReponder and that would stop the repeating. For the playSound case, the user would realize what is happening and take her finger off of the key.
That said, there are real cases where specific keys should never repeat. It would be nice if Apple provided a public API for that. As far as I can tell, they do not.
Given the '//Not allowed in the AppStore' comment in your code, it seems like you're OK using a private API. In that case, you could disable repeating for a keyCommand with:
UIKeyCommand *keyCommand = [UIKeyCommand ...];
[keyCommand setValue:@(NO) forKey:@"_repeatable"];
回答2:
I reworked @Ely's answer a bit:
extension UIKeyCommand {
var nonRepeating: UIKeyCommand {
let repeatableConstant = "repeatable"
if self.responds(to: Selector(repeatableConstant)) {
self.setValue(false, forKey: repeatableConstant)
}
return self
}
}
Now you can have to write less code. If for example just override var keyCommands: [UIKeyCommand]?
by returning a static list it can be used like this:
override var keyCommands: [UIKeyCommand]? {
return [
UIKeyCommand(...),
UIKeyCommand(...),
UIKeyCommand(...),
UIKeyCommand(...).nonRepeating,
UIKeyCommand(...).nonRepeating,
UIKeyCommand(...).nonRepeating,
]
}
This makes the first three command repeating (like increasing font size) and the last three ones non repeating (like sending an email).
Works with Swift 4, iOS 11.
回答3:
This works in iOS 12, a little bit less 'private' compared to the accepted answer:
let command = UIKeyCommand(...)
let repeatableConstant = "repeatable"
if command.responds(to: Selector(repeatableConstant)) {
command.setValue(false, forKey: repeatableConstant)
}
来源:https://stackoverflow.com/questions/41731442/stop-uikeycommand-repeated-actions