简体   繁体   English

停止UIKeyCommand重复操作

[英]Stop UIKeyCommand repeated actions

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. 这可能会产生非常奇怪的效果,例如⌘N可能会多次重复打开一个新视图。 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 可以在此处下载示例项目: TestKeyCommands.zip

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. 对于playSound案例,用户会意识到正在发生的事情,并将她的手指从钥匙上移开。

That said, there are real cases where specific keys should never repeat. 也就是说,有些情况下特定键不应重复。 It would be nice if Apple provided a public API for that. 如果Apple提供了一个公共API,那将是很好的。 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. 鉴于您的代码中的“// AppStore中不允许”注释,您似乎可以使用私有API。 In that case, you could disable repeating for a keyCommand with: 在这种情况下,您可以禁用对keyCommand的重复:

UIKeyCommand *keyCommand =  [UIKeyCommand ...];
[keyCommand setValue:@(NO) forKey:@"_repeatable"];

This works in iOS 12, a little bit less 'private' compared to the accepted answer: 这适用于iOS 12,与接受的答案相比,它更“私密”:

let command = UIKeyCommand(...)   
let repeatableConstant = "repeatable"
if command.responds(to: Selector(repeatableConstant)) {
    command.setValue(false, forKey: repeatableConstant)
}

I reworked @Ely's answer a bit: 我重新修改了@Ely的答案:

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]? 例如,如果只是覆盖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 . 适用于Swift 4,iOS 11

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM