Stupid UIAlertView Tricks Part Deux

Another Stackoverflow question has prompted me to yet again revisit the issue of putting random views into a UIAlertView.

If you missed my previous installments, check out UIAlertView with UITextField (which is actually moderately useful at times), and UIAlertView with UIWebView, which is pretty much not good for anything except guffaws.

In this installment, we’ll jam a UITableView in there, and even throw in some UISwitch controls for good measure.

Note: never do this. Though I don’t believe it’s a direct violation of the Almighty Apple Book Of Holiness Human Interface Guidelines, it would surely make most iPhone UI Geeks cringe. I’m not a UI hardliner, but I wouldn’t do this in one of my apps. Neither Fat Apps, nor myself are responsible for any App Store rejections, loss of life, loss of limb, or loss of credibility that may result from using this code in an actual app. This is for fun.

Now then. Much like putting any other random view in an alert view, there’s really not that much work to do beyond what you’d normally do if you were making such a view without the alert view. In the case of a UITableView, you need to have a class which implements UITableViewDataSource. Create the cells in tableView:cellForRowAtIndexPath:, and add your controls as the accessoryView, like so:

- (UITableViewCell*) tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
    static NSString* const SwitchCellID = @"SwitchCell";
    UITableViewCell* aCell = [tableView dequeueReusableCellWithIdentifier:SwitchCellID];
    if( aCell == nil ) {
        aCell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:SwitchCellID] autorelease];
        aCell.textLabel.text = [NSString stringWithFormat:@"Option %d", [indexPath row] + 1];
        aCell.selectionStyle = UITableViewCellSelectionStyleNone;
        UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectZero];
        aCell.accessoryView = switchView;
        [switchView setOn:YES animated:NO];
        [switchView addTarget:self action:@selector(soundSwitched:) forControlEvents:UIControlEventValueChanged];
        [switchView release];
    }

    return aCell;
}

There’s no magic here: it’s what I do in the PuzzleTiles options screen, and it’s what Apple does in the Settings app. No big whoop.

Alright, now let’s jam this bad boy into an alert view.

- (void) doAlertWithTableView
{
    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Preferences" 
                        message:@"\n\n\n\n\n\n\n"
                       delegate:self 
              cancelButtonTitle:@"Cancel"
              otherButtonTitles:@"OK", nil];

    UITableView* myView = [[[UITableView alloc] initWithFrame:CGRectMake(10, 40, 264, 150) 
              style:UITableViewStyleGrouped] autorelease];
    myView.delegate = self;
    myView.dataSource = self;
    myView.backgroundColor = [UIColor clearColor];
    [alert addSubview:myView];

    [alert show];
    [alert release]; 
}

That’s it! The only real trick (just like with a UITextField or a UIWebView, is to put some linefeeds in your message to make the alert taller to fit your view.

Here’s how she looks:

Uialert with table

Next time I’ll try writing a post that doesn’t feature a UIAlertView! Yay!

If you want to follow me, I’m @zpasternack on Twitter and on app.net.

Stupid UIAlertView Tricks: Part I

Earlier this evening I was answering a StackOverflow question about putting a UITextView onto a UIAlertView. I had done this before with UITextFields (I wrote a post about it), but I’d never tried it before with a UITextView. Well, it turns out to totally work.

However, it got me thinking about jamming random other views into a UIAlertView. The logical conclusion of which was this: StackOverflow in a UIAlertView.

StackOverflow in a UIAlertView

Why? I dunno. Cool though, right?

- (void) doAlertViewWithWebView
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"stackoverflow"
                   message:@"\n\n\n\n\n\n\n\n\n\n\n\n"
                  delegate:nil
         cancelButtonTitle:nil
         otherButtonTitles:@"OK", nil];

    UIWebView *myView = [[[UIWebView alloc] initWithFrame:CGRectMake(10, 40, 264, 254)] autorelease];
    myView.scalesPageToFit = YES;
    [alert addSubview:myView];

    [myView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.stackoverflow.com"]]];

    [alert show];
    [alert release];
}

If you want to follow me, I’m @zpasternack on Twitter and on app.net.

UIAlertView with UITextField

Note: While this technique still works, there is (since iOS 5) an easier way to put a text field on an alert view, as I’ve written about here.

It’s sometimes useful to display an alert with a text box for simple data entry.  It’s simple, effective, and is a pretty reasonable UI, in my opinion.  For example, PuzzleTiles does this as kind of a ghetto name entry prompt for adding your name to the high score list.

Fortunately, Apple provides an API for adding text fields to alert views.  Unfortunately, they’re private.  It used to be you could sneak that by the app review team, but those days are over.  Your app will be rejected if you use these calls, take it from me.

Good news, though: manually adding your own text field to an alert view is easy, and fun.  Dig it:

#define kTag_EnterNameAlert  1
#define kTag_NameEmtryField  100

- (void) doAlertWithTextField
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Congratulations!" 
                     message:@"You earned a top score! Enter your name:\n\n"
                    delegate:self 
           cancelButtonTitle:nil
           otherButtonTitles:@"OK", nil];
    alert.tag = kTag_EnterNameAlert;

    CGRect entryFieldRect = CGRectZero;
    if( UIDeviceOrientationIsPortrait( [UIApplication sharedApplication].statusBarOrientation ) ) {
        entryFieldRect = CGRectMake(12, 90, 260, 25);
    }
    else {
        entryFieldRect = CGRectMake(12, 72, 260, 25);
    }

    UITextField *nameEntryField = [[UITextField alloc] initWithFrame:entryFieldRect];
    nameEntryField.tag = kTag_NameEmtryField;
    nameEntryField.backgroundColor = [UIColor whiteColor];
    nameEntryField.keyboardType = UIKeyboardTypeAlphabet;
    nameEntryField.keyboardAppearance = UIKeyboardAppearanceAlert;
    nameEntryField.autocorrectionType = UITextAutocorrectionTypeNo;
    nameEntryField.clearButtonMode = UITextFieldViewModeWhileEditing;
    [alert addSubview:nameEntryField];
    [nameEntryField becomeFirstResponder];
    [nameEntryField release];

    [alert show];
    [alert release];
}

You more-or-less make a UITextField and add it to the UIAlertView via addSubview:. There are some things to note, in no particular order:

  • Put some extra linefeeds at the end of your message.  This will make the alert view taller, which makes room for the text field.  You’ll need to play around with it to get it looking just right.
  • You’re going to need to hardcode the coordinates of the text field, and depending on the message, the location might need to change.  Again, play with it.  Don’t half-ass it; iPhone apps need to be pretty.  Note that if you support landscape mode, the layout will be ever-so-slightly different.
  • Set the text field’s keyboardAppearance to UIKeyboardAppearanceAlert; otherwise the keyboard will overlap with the alert.
  • If you’re expecting the user to enter a name, you probably want to turn off autocorrection by setting the text field’s autocorrectionType to UITextAutocorrectionTypeNo
  • If you intend to do something with the text later, set the text field’s tag so you can easily retrieve it later (like, in alertView:willDismissWithButtonIndex:.

The result looks like this:

UIAlertView with UITextField

If you want to follow me, I’m @zpasternack on Twitter and on app.net.