Combining multiple UITextFields and a UITableView in a nice way for an iPhone app

Update: also read Part 2 explaining a different way of solving this problem.

So a decent number of iPhone apps will not only show things like data, but also offer you the possibility to edit data. Many controls like UISlider, UISwitch and UITextfield are provided by Apple to create some type of edit screen, almost like a web form on a HTML page. Creating a simple form that only covers the top half of your screen is simple: you create your elements like UITextField at the top, and when you touch inside the field the onscreen keyboard will show up. You hit a Done Button or a non-UITextField control and the keyboard disappears again.

Now, when you have more data to add/edit than will fit in half a screen, things get more daunting:

  1. the keyboard should only be visible when editing a UITextField
  2. when touching a UITextField so that the keyboard becomes visible, it should not cover the field you are editing
  3. with the keyboard visible you should still be able to scroll to all elements of your editing form, and not have parts be covered indefinitely by the keyboard

Well, the most natural kind of view to use to display all controls is a UITableView. Apple uses it herself, look at the editing screen for your Mail.app settings. But when you just throw in a UITableView, you run into problems:

  1. when scrolling off screen, table cells are reused and therefore also its subviews like UITextFields, which causes your newly entered data to be destroyed
  2. when having a UITextField being firstResponder (cursor in it),  you scroll it off screen and the touch inside another UITextField that then becomes firstResponder, your app will crash. This is problably because the first UITextField is destroyed before it can resignFirstResponder

So how do we do this then? Apple does use a UITableView in some way, but the above problems are show stoppers. Well the answer is: use a UITableView, but don’t let it scroll.


The trick is to nest a UITableView inside a UIScrollView. And then to give the table and the contentSize of exactly the same size that the whole form is. So if you have 10 cells each 44 pixels high, you create a UITableView with a height of 440, and put that inside a UIScrollView with a contentSize that is also 440 pixels high. This way the table is exactly the size of all the cells combined. This way no scrolling for the UITableView and therefore no reuse of cell’s with all it’s problems.

nesting_uitableview_inside_uiscrollview

Here’s the code to set the size correctly:

// actually more object in reality

self.countries = [[NSMutableArray alloc]initWithObjects: @”Belgium”, @”Brittain”,nil];

[self.scrollView setContentSize:CGSizeMake(320, (CELL_HEIGHT * [self.countries count]))];

[self.tableView setFrame:CGRectMake(0, 0, 320, (CELL_HEIGHT * [self.countries count]))];

Well, that’s the main trick. Added to that, you want to resize the frame when the onscreen keyboard is shown and scroll the UITextField you touched in to scroll into view. Have a look at the source code to see how that’s done.

Download TextfieldsWithKeyboard XCode iPhone project

12 thoughts on “Combining multiple UITextFields and a UITableView in a nice way for an iPhone app

  1. Just a question. Wont doing that mean it all stays in memory and results in slow scroll performance? I have an app that requires up to 50 lines of input involving UITextFields, and a switch and am currently using a UIScrollview but the scrolling is no longer smooth as soon as you start adding UITextfields as subviews.

  2. Yes, that would keep the actual data in memory. I do not think the 50 lines of input causes the problems, that’s with UTF-8 maybe 50 * 60 * 2 = 6k of data. Any given moment an app will use 10-20mb of memory, so 6k is not a lot.

    Look at incorrect overlaps/sizes of subviews in views, too many transparent views etc to fix your problems.

    dirk

  3. > Wont doing that mean it all stays in memory and results in slow scroll performance?

    “Using more memory” and “slow scrolling”… are NOT the same things.

    Which sounds faster:
    1. Drawing it once… use a little memory… and just scroll it around.

    2. Save a little memory… and alloc ever cell… over and over… or dealloc… and reuse… and redesign ever cell… countless times.

  4. All you need to do is retain the cells you’ve added, so they don’t get released when they scroll out of view. You should read the documentation for UITableView- it’s all in there. Look at the cell reuse mechanism as well, which is designed to reduce memory consumption with large tables.

  5. @chris, yes see part 2 for a way of doing this, the UITableView reuse of cells is very good when you want to scroll through 100s of rows, not for making form-like views

    @daniele looks good, I’l give it a go

  6. I have found out a idea resolution for this issue in all cases,

    here are some steps for that;
    1. UITableViewCell should have a weak reference property to the view controller that involves itself.
    2. in that view controller, add a property (retained) for the current first responder (UITextView or UITextField type).
    3. 2. in the – (void)textViewDidBeginEditing: method of UITextView or UITextField, assign self to TextField property of the view controller.

    this will solve your problems 🙂

    I hope this will help you !!!

  7. The main difference between this piece and Apple’s lies in the if condition. I believe apple’s calculation of scroll distance and condition of whether text field covered by keyboard are not accurate, so I made my modification as above.

Comments are closed.