UITextField in UIAlertView on iPhone - how to make it responsive?
Asked Answered
G

10

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

Goosestep answered 17/12, 2008 at 21:33 Comment(1)
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!Carping
G
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.

Goosestep answered 18/12, 2008 at 0:30 Comment(5)
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.Vessel
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.Rumanian
@Rumanian for the sake of posterity, I removed the retain which led to a memory leak.Quyenr
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?Coatee
@Coatee make sure your setMessage is " " and not "". It worked for me on 4.3Traceytrachea
T
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]);
}
Traceytrachea answered 20/1, 2012 at 0:41 Comment(2)
about time we get a way to do this that does not involve hacking the stupid alertView. +1Enure
@Enure Very true! Did you do a feature request at bugreports?Bluebill
G
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.

Goosestep answered 18/12, 2008 at 0:30 Comment(5)
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.Vessel
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.Rumanian
@Rumanian for the sake of posterity, I removed the retain which led to a memory leak.Quyenr
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?Coatee
@Coatee make sure your setMessage is " " and not "". It worked for me on 4.3Traceytrachea
L
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.

Lobar answered 9/2, 2009 at 5:49 Comment(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.Vegetation
Broken under simulator 4.3. It crashes the app.Jugurtha
M
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];
Midden answered 8/1, 2009 at 5:29 Comment(0)
C
3

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

Cachet answered 11/12, 2009 at 19:58 Comment(0)
U
2

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

Unpredictable answered 13/4, 2011 at 23:44 Comment(0)
I
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;
}
Intersidereal answered 19/11, 2009 at 9:35 Comment(0)
S
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);
}
Subalpine answered 18/7, 2012 at 11:42 Comment(0)
L
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

Lanneret answered 20/1, 2012 at 0:57 Comment(0)
N
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.

Nipa answered 1/8, 2012 at 8:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.