Question

In my app I have a UITextField on the navigationController toolbar.

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic,strong) NSArray *toolBarButtonItems;
@property (nonatomic,strong) UITextField *textField;
@property (nonatomic,strong) UITextField *textField2;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    self.textField = [[UITextField alloc]initWithFrame:CGRectMake(0, 0, 60, 40)];
    self.textField.delegate = self;
    self.textField.borderStyle = UITextBorderStyleRoundedRect;

    UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
    UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc]initWithCustomView:self.textField];

    self.toolBarButtonItems = @[flexibleSpace,barButtonItem,flexibleSpace];

    self.toolbarItems = self.toolBarButtonItems;
    self.navigationController.toolbar.barTintColor = [UIColor blueColor];

    [self.navigationController setToolbarHidden:NO animated:NO];
}

When the textField is clicked the keyboard opens up and I create a new inputAccessoryView toolbar with another textField.

-(UIToolbar *)addToolBar{
    UIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:self.navigationController.toolbar.frame];
    toolbar.barTintColor = [UIColor darkGrayColor];

    self.textField2 = [[UITextField alloc]initWithFrame:CGRectMake(0, 0, 60, 40)];
    self.textField2.delegate = self;
    self.textField2.borderStyle = UITextBorderStyleRoundedRect;

    UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
    UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc]initWithCustomView:self.textField2];

    [toolbar setItems:@[flexibleSpace,barButtonItem,flexibleSpace]];
    return toolbar;
}

The idea is to change the firstResponder to the textField on the inputAccessoryView so this way I can see what I'm editing. The reason I am doing this is cause I can't scroll the Navigation toolbar up past the keyboard and I want to see the text that I am editing.

-(void)textFieldDidBeginEditing:(UITextField *)textField{
    textField.inputAccessoryView = [self addToolBar];

    if(self.textField2.isFirstResponder != NO){
        [self.textField2 becomeFirstResponder];
    }
}

It doesn't seem to be working when I click on the textField in the navigationController toolbar. The new inputAccessoryView toolbar shows up over the keyboard but I can't edit the field because the responder doesn't seem to be changing. The return key doesn't work either. I have to hit it twice in order to close the keyboard and when I do the text doesn't match up between the two text fields.

-(BOOL)textFieldShouldReturn:(UITextField *)textField{
    [textField resignFirstResponder];
    self.textField.text = self.textField2.text;
    return YES;
}
Was it helpful?

Solution

I got it to work like this:

#import "KJMViewController.h"

@interface KJMViewController ()

@property (strong, nonatomic) UITextField *textField1;
@property (strong, nonatomic) UITextField *textField2;

@end

@implementation KJMViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.textField1 = [[UITextField alloc]initWithFrame:CGRectMake(30, 7, 260, 30)];
    self.textField1.borderStyle = UITextBorderStyleRoundedRect;
    self.textField1.delegate = self;
    UIToolbar *navToolbar = self.navigationController.toolbar;
    [navToolbar addSubview:self.textField1];

    UIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 44)];
    self.textField2 = [[UITextField alloc]initWithFrame:CGRectMake(30, 7, 260, 30)];
    self.textField2.borderStyle = UITextBorderStyleRoundedRect;
    self.textField2.delegate = self;
    [toolbar addSubview:self.textField2];
    self.textField1.inputAccessoryView = toolbar;
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(firstRes:) name:UIKeyboardDidShowNotification object:nil];
}

- (void)firstRes:(id)sender
{
    [self.textField2 becomeFirstResponder];
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{

}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    if (textField == self.textField2) {
        self.textField1.text = self.textField2.text;
    }
    [textField resignFirstResponder];
    [self.textField1 resignFirstResponder];
    return YES;
}

- (void)viewDidDisappear:(BOOL)animated
{
    [[NSNotificationCenter defaultCenter]removeObserver:self forKeyPath:UIKeyboardDidShowNotification];
    [super viewDidDisappear:animated];
}

@end

Here's what's happening in viewDidLoad:

  • Initialise toolbar and textField2
  • Set the inputAccessory for textField1 (the one hidden by the keyboard) here so it's ready to become firstResponder

Then in the viewDidAppear method:

Sign up for a notification that's sent when the keyboard is shown. You'll then write some code in the "firstRes" method to make textField2 the firstResponder. You need to make it the firstResponder using this notification because you know that it's in the view hierarchy by this time, which means it's able to become firstResponder. Calling it in the -(void)textFieldDidBeginEditing:(UITextField *)textField seems to fire it before textField2 comes on screen, meaning that it can't become firstResponder. We sign up for it in the viewDidAppear method because we only want to get the notification if we're on screen.

After textField2 resignsFirstResponder, textField1 becomes first responder again, so you have to call resignFirstResponder twice in the textFieldShouldReturn method.

Also, if we leave the screen, we need to remove ourself as an observer of the keyboard notification in the viewDidDisappear method.

Here's a link to the project I made in Xcode so you can see how it works:

https://github.com/kylejm/UIToolBar-UITextView

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top