能否通过编程方式提供iOS预测键盘的上下文/源文本?

14

我正在开发一款消息应用程序,并希望iOS 8中的预测键盘能够识别撰写消息的用户正在回复上一条消息。

所以我想要能够向键盘提供上下文信息以便进行预测。例如,如果用户被问及可解释为极性(是/否)的问题,则预测键盘应该有Yes | No | Maybe

开发人员可以使用这个吗?

请注意,我指的不是自定义键盘,只是给标准键盘提供一些上下文信息以进行预测。我也不关心实际定制快速回复类型就像这个问题。我只是希望键盘知道它正在输入什么内容。

2个回答

16
严格来说,无法直接向默认键盘输入建议。但是,如果您想为用户提供等效的体验,可以使用myTextView.autocorrectionType = UITextAutocorrectionTypeNo;隐藏iOS建议栏,然后用自定义视图替换该视图,模仿建议视图。一旦用户键入字符或选择选项,就隐藏自定义建议视图并重新启用iOS建议栏。我为此子类化了UIInputView(透明度和转换可能有些问题,但其他方面都运行得很好)。
#import <UIKit/UIKit.h>

@protocol SuggestionViewDelegate <NSObject>

@required
- (void)suggestionSelected:(NSString *)suggestion;

@end

@interface SuggestionView : UIInputView

- (instancetype)init;
- (instancetype)initWithFrame:(CGRect)frame;

/**
 *  The list of suggestions being displayed.
 *  The array contains 0-3 strings.
 *
 *  @return Array of NSString's representing the current suggested strings
 */
- (NSArray *)suggestions;

/**
 *  Add a suggestion to display in the view.
 *  If there are already maxSuggestionCount suggestions, the added suggestion will push one of them out.
 *  If there are already maxSuggestionCount suggestions and the input is 'nil' then the last suggestion will be removed.
 *
 *  @param suggestion String to suggest to the user
 */
- (void)addSuggestion:(NSString *)suggestion;

/**
 *  Removes the suggestion from the list of displayed suggestions.
 *  If the string is not in the set then there is no change made.
 *
 *  @param suggestion NSString to remove from the suggested strings
 */
- (void)removeSuggestion:(NSString *)suggestion;

/**
 *  Takes in either NSArray or NSSet and replaces 'suggestions' with the input. 
 *  Only the first three arguments are recognized.
 *  Objects should be strings. Undefined behavior otherwise.
 *
 *  @param suggestions NSArray or NSSet with 0-3 NSStrings
 */
- (void)setSuggestions:(NSObject *)suggestions;

@property (weak) id <SuggestionViewDelegate> delegate;

/**
 *  The maximum number of suggestions allowed. Default is 3.
 */
@property (nonatomic) NSInteger maxSuggestionCount;

@end

#import "SuggestionView.h"

#define kScreenWidth [UIScreen mainScreen].bounds.size.width

@implementation SuggestionView {
    NSMutableOrderedSet *_suggestions;
    NSMutableArray *_suggestionButtons;
}

- (instancetype)init {
    self = [self initWithFrame:CGRectMake(0.0f, 0.0f, kScreenWidth, 36.0f)];

    if (self) {

    }

    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame inputViewStyle:UIInputViewStyleKeyboard];

    if (self) {
        _suggestions = [[NSMutableOrderedSet alloc] initWithCapacity:3];
        self.maxSuggestionCount = 3;
        _suggestionButtons = [[NSMutableArray alloc] init];
        self.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.04f];
    }

    return self;
}

#pragma mark - Modifying Suggestions

- (void)addSuggestion:(NSString *)suggestion {
    if (suggestion) {
        [_suggestions addObject:suggestion];
    }

    while (_suggestions.count > self.maxSuggestionCount) {
        [_suggestions removeObjectAtIndex:self.maxSuggestionCount];
    }
}

- (void)removeSuggestion:(NSString *)suggestion {
    [_suggestions removeObject:suggestion];
}

- (void)setSuggestions:(NSObject *)suggestions {
    if ([suggestions respondsToSelector:@selector(countByEnumeratingWithState:objects:count:)]) {
        [_suggestions removeAllObjects];

        for (NSString *suggestion in (NSArray *)suggestions) {
            if (_suggestions.count < self.maxSuggestionCount) {
                [_suggestions addObject:suggestion];
            } else {
                break;
            }
        }
    }
}

- (NSArray *)suggestions {
    NSMutableArray *suggestionsArray = [[NSMutableArray alloc] initWithCapacity:_suggestions.count];
    for (NSString *suggestion in _suggestions) {
        [suggestionsArray addObject:suggestion];
    }

    return suggestionsArray;
}

#pragma mark - Visual Layout of Suggestions

- (void)layoutSubviews {
    [self layoutSuggestions];
}

- (void)layoutSuggestions {
    for (UIView *subview in _suggestionButtons) {
        [subview removeFromSuperview];
    }

    [_suggestionButtons removeAllObjects];

    for (int i = 0; i < _suggestions.count; i++) {
        NSString *suggestion = _suggestions[i];
        UIButton *suggestionButton = [[UIButton alloc] initWithFrame:CGRectMake(i * self.bounds.size.width/_suggestions.count, 0.0f, self.bounds.size.width/_suggestions.count, self.bounds.size.height)];
        [suggestionButton setTitle:suggestion forState:UIControlStateNormal];
        suggestionButton.titleLabel.adjustsFontSizeToFitWidth = YES;
        suggestionButton.titleLabel.textAlignment = NSTextAlignmentCenter;
        [suggestionButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [suggestionButton addTarget:self action:@selector(buttonTouched:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:suggestionButton];

        if (i > 0) {
            UIView *whiteLine = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.5f, self.bounds.size.height)];
            whiteLine.backgroundColor = [UIColor whiteColor];
            [suggestionButton addSubview:whiteLine];
        }

        [_suggestionButtons addObject:suggestionButton];
    }
}

#pragma mark - Selecting a Suggestion

- (void)buttonTouched:(UIButton *)button {
    NSTimeInterval animationDuration = 0.09f;
    [UIView animateWithDuration:animationDuration animations:^{
        [button setBackgroundColor:[UIColor whiteColor]];

        if ([self.delegate respondsToSelector:@selector(suggestionSelected:)]) {
            [self performSelector:@selector(suggestionSelected:) withObject:button.currentTitle afterDelay:animationDuration * 0.9f];
        }

        [button performSelector:@selector(setBackgroundColor:) withObject:[UIColor clearColor] afterDelay:animationDuration];
    }];
}

- (void)suggestionSelected:(NSString *)suggestion {
    if ([self.delegate respondsToSelector:@selector(suggestionSelected:)]) {
        [self.delegate suggestionSelected:suggestion];
    }
}

@end

如果您已经子类化了UITextFieldUITextView,并希望将此功能实现到它们中,可以导入SuggestionView并实现SuggestionViewDelegate。然后,在UITextFieldDelegate(或UITextViewDelegate)方法中添加以下内容:

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    if ([textField isEqual:self.messageTextField]) {
        if (self.suggestionView.suggestions.count > 0 && textField.text.length == 0) {
            textField.inputAccessoryView = self.suggestionView;
            textField.autocorrectionType = UITextAutocorrectionTypeNo;
            [textField reloadInputViews];
        }
    }

    return YES;
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if ([textField isEqual:self.messageTextField]) {
        if (string.length > 0) {
            [self removeSuggestionView];
        }
    }

    return YES;
}


- (void)removeSuggestionView {
    self.messageTextField.inputAccessoryView = nil;
    [self.messageTextField setInputAccessoryView:nil];
    self.messageTextField.autocorrectionType = UITextAutocorrectionTypeYes;
    [self.messageTextField reloadInputViews];

    [self.messageTextField performSelector:@selector(resignFirstResponder) withObject:self afterDelay:0.0f];
    [self.messageTextField performSelector:@selector(becomeFirstResponder) withObject:self afterDelay:0.0f];
}

然后,实现SuggestionViewDelegate

- (void)suggestionSelected:(NSString *)suggestion {
    [self.messageTextField setText:[NSString stringWithFormat:@"%@%@ ", self.messageTextField.text, suggestion]];
    [self removeSuggestionView];
}

虽然这并不是一个完美的解决方案,但它确实能够产生所需的效果。

3
虽然我希望有人会出现并说,“是的,这是可能的,只需要做XYZ”,但这是一个非常好的答案。感谢您分享您的代码和方法-我只是希望苹果能够开放这个功能,虽然我认为这只是一个小的奖励,用消息应用代替WhatsApp、FB Messenger、Kik等等。 - sbauch

4
由于在官方Apple文档中找不到如何做到这一点的进一步信息,我想这是不可能的。但是您有两个选择:
  • 保留标准键盘并手动显示一个条形(在UIView实例内)在其上方。
  • 从头开始创建自定义键盘(更加困难)。您可以在此处阅读更多

您还可以考虑完全不同的用户体验。例如,如果您的用户可能会选择您的建议之一,则仅呈现这些建议并保留一个小按钮以输入自定义内容(并在此处关闭键盘)。如果用户可能输入自定义输入,请参考上述两种替代方法。


这是一个非常简洁的答案(尽管不是我想听到的!啊啊啊!!!),所以谢谢你。我没有创建悬赏,但感觉有义务选择另一个答案作为“最正确的”。我认为完全不同的用户体验不适用于我(在这种情况下),因为我有意识地试图使一个可以轻松成为2个按钮的输入更像是NLP / 对话式输入。 - sbauch
没问题,希望你能够得到你所需要的答案! - sweepy_

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接