Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Customise the quicktype suggestions in iOS Keyboard

I want to have quicktype suggestions to have my own certain application level needed phrases as suggestions when keyboard is open in uitextview.

For example if user types "All" - In quicktype suggesstion I want to show "All is well" or "All is as expected".

Can I customize the quicktype suggestion text?

If not, what could be other way to have this suggestions to show when keyboard is open.

like image 844
AKG Avatar asked Feb 04 '15 07:02

AKG


People also ask

How do I change keyboard suggestions in iOS?

Tap Keyboard Settings, then turn on Predictive. Or go to Settings > General > Keyboard, and turn Predictive on or off. See a full list of languages that support predictive text.


1 Answers

Since there's no (known) way of changing the quicktype suggestions, I Subclassed UIInputView to allow for custom suggestions as an input accessory view (the transparency and the transition is a little off, but everything else works pretty well).

NOTE: This does not work if you already have an input accessory view on your UITextField or UITextView.

#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

To implement this into a UITextField or UITextView that you've already subclassed, import the SuggestionView and implement the SuggestionViewDelegate. Then, in the UITextFieldDelegate (or UITextViewDelegate) methods, add:

- (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];
}

Then, implement the SuggestionViewDelegate:

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

While this isn't a perfect solution, it does create the desired effect.

like image 80
Fennelouski Avatar answered Sep 22 '22 08:09

Fennelouski