24

I placed a UITextField into a UIAlertView and moved it up so the keyboard wouldn't cover it up with the following code:

[dialog setDelegate:self];
[dialog setTitle:@"Enter Name"];
[dialog addButtonWithTitle:@"Cancel"];
[dialog addButtonWithTitle:@"OK"];
UITextField * nameField = [[UITextField alloc] initWithFrame:CGRectMake(20.0, 45.0, 245.0, 25.0)];
[nameField setBackgroundColor:[UIColor whiteColor]];
[dialog addSubview:nameField];
CGAffineTransform moveUp = CGAffineTransformMakeTranslation(0.0, 100.0);
[dialog setTransform: moveUp];
[dialog show];

I also have the following code to deal with the alert view:

- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex{    
    NSLog(@"%d", (int) buttonIndex);
    if (buttonIndex == 1) { // OK pushed
        NSLog([alert textField].text); // does not log anything
    } else {
        // Cancel pushed
}}

I also have a UIAlertViewExtended.h file that contains:

@class UITextField, UILabel;

@interface UIAlertView(Extended)

-(UITextField *)textField;

@end

My question is how do I get the text the user entered and how do I dismiss the keyboard?

Thanks, Ben

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
user21293
  • 6,439
  • 11
  • 44
  • 57
  • 3
    iPhone OS 4.0 seems to do the transformation stuff automatically, probably we will have to introduce a check if your base SDK is 4.0 and the minimum SDK you will support is 3.0 so that the CGAffineTransform code is executed only if the native OS is 3.0 or 3.1, for iPhone OS 4.0 skip this part of code! – Raj Pawan Gumdal Jul 19 '10 at 07:23

10 Answers10

49

Anyone supporting iOS 5.0 onwards with ARC, there's this direct alertViewStyle property you can set:

-(void)showAlertWithTextField{
    UIAlertView* dialog = [[UIAlertView alloc] initWithTitle:@"Enter Name" message:@"" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Add", nil];    
    [dialog setAlertViewStyle:UIAlertViewStylePlainTextInput];

    // Change keyboard type
    [[dialog textFieldAtIndex:0] setKeyboardType:UIKeyboardTypeNumberPad];
    [dialog show];
}

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    if (buttonIndex == 1)
        NSLog(@"%@",[[alertView textFieldAtIndex:0]text]);
}
Alex
  • 7,432
  • 20
  • 75
  • 118
chunkyguy
  • 3,509
  • 1
  • 29
  • 34
31

For those who may care, here's a working solution:

UIAlertView* dialog = [[UIAlertView alloc] init];
[dialog setDelegate:self];
[dialog setTitle:@"Enter Name"];
[dialog setMessage:@" "];
[dialog addButtonWithTitle:@"Cancel"];
[dialog addButtonWithTitle:@"OK"];

nameField = [[UITextField alloc] initWithFrame:CGRectMake(20.0, 45.0, 245.0, 25.0)];
[nameField setBackgroundColor:[UIColor whiteColor]];
[dialog addSubview:nameField];
CGAffineTransform moveUp = CGAffineTransformMakeTranslation(0.0, 100.0);
[dialog setTransform: moveUp];
[dialog show];
[dialog release];
[nameField release];

Make sure you've created UITextField * nameField; in your .h file, then you can get at the text the user typed in by doing: inputText = [nameField text];

in the - (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex method.

important note: for iOS 4.0+, the CGAffineTransform is done automatically so you can leave that bit out if you're only targeting 4.0+. Otherwise, you will need to check which OS you are on and handle it accordingly.

iwasrobbed
  • 46,496
  • 21
  • 150
  • 195
user21293
  • 6,439
  • 11
  • 44
  • 57
  • Ok, that works pretty well, but how do I get the buttons to move down to make room for the text field? On my implementation (which starts as a copy/paste of yours), I have 4 buttons (Cancel, foo, bar, baz), and the text field overlays the cancel button. – Olie Dec 18 '08 at 16:42
  • 6
    Hey! Why are you retaining the variable `dialog`? Isn't it already allocated by you? I might be wrong but it seems that you are leaking an object this way. The rule of thumb is that if you alloc an object then you must release it because it already has a retain count of 1. – inkredibl May 27 '09 at 13:59
  • 1
    @inkredibl for the sake of posterity, I removed the retain which led to a memory leak. – Epaga Oct 24 '10 at 16:47
  • In iOS 4.2 this will create a alertview on top.Also removing the CGAffineTransform do not sort out the problem.Does anybody have some solution? – raaz Jan 29 '11 at 21:31
  • @raaz make sure your setMessage is " " and not "". It worked for me on 4.3 – chunkyguy Jan 20 '12 at 23:21
14

It's worth checking out

http://junecloud.com/journal/code/displaying-a-password-or-text-entry-prompt-on-the-iphone.html?cmd=success#comment3870

For a complete and comprehensive solution.

Adam Ernst
  • 52,440
  • 18
  • 59
  • 71
  • 2
    Great code. I recommend saving the text field in an instance variable. Then, you don't need to implement the text field delegate and you can have it resign first responder in `alertView:willDismissWithButtonIndex:` to get rid of the "wait_fences: failed to receive reply: 10004003" console messages. – gerry3 May 12 '10 at 06:56
  • Broken under simulator 4.3. It crashes the app. – nemesys Aug 17 '11 at 01:43
6

A simple way to locate the text field, without keeping an explicit reference to it, is to set its tag:

nameField.tag = ALERTVIEW_NAMEFIELD;

Make sure it is different from 0 and from other UIView object tags you may have, including the parent dialog!

Then inside the alertView:clickedButtonAtIndex: handler, you can retrieve your text field this way:

UITextField *nameField = (UITextField *)[alertView viewWithTag:ALERTVIEW_NAMEFIELD];
squelart
  • 11,261
  • 3
  • 39
  • 43
3

Found more clear solution. Check this code snippet out: Username and Password UITextFields in UIAlertView prompt

slatvick
  • 1,207
  • 2
  • 16
  • 25
2

Check out this implementation: https://github.com/josecastillo/EGOTextFieldAlertView

gonso
  • 2,065
  • 5
  • 27
  • 35
1

This is for iOS5 and ARC.

-(void)showAlert {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"New Album" 
        message:@"Enter a name for the album." 
        delegate:self 
        cancelButtonTitle:@"Cancel" 
        otherButtonTitles:@"Save", nil];
    alertView.alertViewStyle = UIAlertViewStylePlainTextInput;

    UITextField* textfield = [alertView textFieldAtIndex:0];
    textfield.placeholder = @"Title";

    [alertView show];
}

-(void)alertView:(UIAlertView *)alertView 
    didDismissWithButtonIndex:(NSInteger)buttonIndex 
{
    if (buttonIndex != 1) {
        NSLog(@"Cancel");
        return;
    }
    UITextField* textfield = [alertView textFieldAtIndex:0];
    NSLog(@"Save. text: %@", textfield.text);
}
neoneye
  • 50,398
  • 25
  • 166
  • 151
1

A quite nice approach is, you can use the delegate methods of the UITextFieldDelegate to move the dialog up only when the keyboard is activated. See below.

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.5]; 
    [UIView setAnimationDelegate:self];

    CGAffineTransform moveUp = CGAffineTransformMakeTranslation(0.0, -20);
    [dialog setTransform: moveUp];

    [UIView commitAnimations];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.5]; 
    [UIView setAnimationDelegate:self];

    CGAffineTransform moveDown = CGAffineTransformMakeTranslation(0.0, 0.0);
    [dialog setTransform: moveDown];

    [textField resignFirstResponder];

    return YES;
}
adam
  • 22,404
  • 20
  • 87
  • 119
0

Would like to add one minor tweak to iWasRobbed's answer:

GenericAlertDialogs.m:

+ (void)displayInputDialog:(NSString*)title delegate:(id<UIAlertViewDelegate>)delegate textFiled:(UITextField*)txtField
{
    UIAlertView* dialog = [[UIAlertView alloc] init];
    [dialog setDelegate:delegate];
    [dialog setTitle:title];
    [dialog setMessage:@" "];
    [dialog addButtonWithTitle:@"Cancel"];
    [dialog addButtonWithTitle:@"OK"];

    if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]))
    {
        txtField.frame = CGRectMake(20.0, 45.0, 245.0, 25.0);
    }
    else 
    {
        txtField.frame = CGRectMake(20.0, 30.0, 245.0, 25.0);
    }

    [txtField becomeFirstResponder];
    [txtField setBackgroundColor:[UIColor whiteColor]];
    [dialog addSubview:txtField];
    [dialog show];   
}

Some other .m file (implements UIAlertViewDelegate)

 self->txtChangeName = [[UITextField alloc] init];
 [GenericAlertDialogs displayInputDialog:@"Some title...:" 
                                delegate:self 
                               textFiled:txtChangeName];

The UIAlertViewDelegate protocol handling:

- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex 
{
    if(buttonIndex == 1)
    {
        if([txtChangeName.text length] > 0)
        {
            self->userInput = [txtChangeName text];
         }
     }
     self->txtChangeName = nil;
}

iOS 4+ compliant.

driedler
  • 3,750
  • 33
  • 26
0

This is actually only 1 more line to the regular UIAlertView code. Hope this helps!

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"test" message:@"This is a alert with a textfield" delegate:self cancelButtonTitle:@"YAY" otherButtonTitles:nil];
    alert.alertViewStyle = UIAlertViewStylePlainTextInput;
    [alert show];
    [alert release];

only runs on iOS 5 or later

Gareth Davis
  • 27,701
  • 12
  • 73
  • 106
Maximilian Litteral
  • 3,059
  • 2
  • 31
  • 41