Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show keyboard with UITextField in the input accessory view

I have a buttonA and when the buttonA is clicked, I want the keyboard to show with a UITextField in the inputAccessoryView. Is there a way to have the keyboard show manually and also set the inputAccessoryView without having a UITextField initially?

Thanks.

like image 314
CLDev Avatar asked Aug 15 '13 20:08

CLDev


People also ask

What is input accessory view?

A component which enables customization of the keyboard input accessory view on iOS. The input accessory view is displayed above the keyboard whenever a TextInput has focus. This component can be used to create custom toolbars.


1 Answers

You cannot summon the keyboard without an object which can become first responder. There are two ways to work around:

  • Subclass a UIView and implement UIKeyInput protocol in it. For example:

    In your .h file:

    @interface InputObject : UIView<UIKeyInput>
    @property (nonatomic, copy) NSString *text;
    @property (nonatomic, strong) UIView *inputAccessoryView; // You must override inputAccessoryView , since it's readonly by default
    @end
    

    In your .m file, implement the protocol:

    - (BOOL)canBecomeFirstResponder
    {
        return YES;
    }
    
    - (BOOL)hasText
    {
        return [self.text length];
    }
    
    - (void)insertText:(NSString *)text
    {
        NSString *selfText = self.text ? self.text : @"";
        self.text = [selfText stringByAppendingString:text];
        [[NSNotificationCenter defaultCenter] postNotificationName:kInputObjectTextDidChangeNotification object:self];
    }
    
    - (void)deleteBackward
    {
        if ([self.text length] > 0)
            self.text = [self.text substringToIndex:([self.text length] - 1)];
        else
            self.text = nil;
        [[NSNotificationCenter defaultCenter] postNotificationName:kInputObjectTextDidChangeNotification object:self];
    }
    

Let's say you want to summon the keyboard in your -viewDidAppear:, the code goes like this:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // inputObject and textField are both your ivars in your view controller
        inputObject = [[InputObject alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
        textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 30)];
        inputObject.inputAccessoryView = textField;
        [self.view addSubview:inputObject];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(inputObjectTextDidChange:) name:kInputObjectTextDidChangeNotification object:nil];

    }

    - (void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
        [inputObject becomeFirstResponder]; // This will summon the keyboard
    }

Then implement the notification selector in your view controller:

    - (void)inputObjectTextDidChange:(NSNotification *)notification
    {
        // Just set the text here. notification.object is actually your inputObject.
        textField.text = ((InputObject *)(notification.object)).text;
    }

This is probably what you mean by "set the inputAccessoryView without having a UITextField initially"

  • Another workaround is to let the textField "pretend" to be the inputAccessoryView by carefully arranging its animation. But this solution needs your textField to be the first responder.

Firstly, you observe the keyboard events in your -viewDidLoad:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Init the textField and add it as a subview of self.view
        textField = [[UITextField alloc] init];
        textField.backgroundColor = [UIColor redColor];
        [self.view addSubview:textField];

        // Register keyboard events
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShowNotification:) name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHideNotification:) name:UIKeyboardWillHideNotification object:nil];
    }

Secondly, set the frame of your textField in -viewWillAppear:, in order to guarantee its frame won't be affected by autoresizing :

    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        textField.frame = CGRectMake(0, CGRectGetMaxY(self.view.bounds), CGRectGetWidth(self.view.bounds), 50);
    }

And then, arrange your textField animation and let it be synchronized with the keyboard animation. Your keyboard notification selectors may be like this:

    - (void)keyboardWillShowNotification:(NSNotification *)notification
    {
        NSDictionary *userInfo = notification.userInfo;
        UIViewAnimationCurve curve = [[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
        CGFloat duration = [[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
        CGRect keyboardFrame = [[userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
        keyboardFrame = [self.view convertRect:keyboardFrame toView:self.view];

        [UIView animateWithDuration:duration delay:0.0f options:(UIViewAnimationOptions)curve animations:^{
            CGRect textFieldFrame = textField.frame;
            textFieldFrame.origin.y = keyboardFrame.origin.y - CGRectGetHeight(textFieldFrame);
            textField.frame = textFieldFrame;
        }completion:nil];
    }

    - (void)keyboardWillHideNotification:(NSNotification *)notification
    {
        NSDictionary *userInfo = notification.userInfo;
        UIViewAnimationCurve curve = [[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
        CGFloat duration = [[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
        [UIView animateWithDuration:duration delay:0.0f options:(UIViewAnimationOptions)curve animations:^{
            textField.frame = CGRectMake(0, CGRectGetMaxY(self.view.bounds), CGRectGetWidth(self.view.bounds), 50);
        }completion:nil];
    }

At last, call [textField becomeFirstResponder] to trigger the animation.

like image 71
liuyaodong Avatar answered Sep 28 '22 09:09

liuyaodong