views:

6409

answers:

6

I have an issue where when a textField is clicked on in a UITableView cell, the method tableView:didSelectRowAtIndexPath: does not get invoked. The problem is, I need to scroll my tableView into proper position, otherwise the keyboard goes right over the first responder.

I have to then move code like this:

[[self tableView] scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];

into both my tableView delegate method and in my UITextField delegate method, textFieldDidBeginEditing:

Is the best way to just create a new method, pass to it the indexPath of the cell/textfield being clicked, and call the method from both the tableView delegate and the UITextField delegate? better way of going about it?

+2  A: 

You can set your controller as the delegate of your UITextField, then adjust your table view in either textFieldDidBeginEditing: or textFieldShouldBeginEditing:

August
August, that's what I'm currently doing. The problem with that is, the scrolling needs to happen in two places. On the tableView:didSelectRowAtIndexPath: method and in the textFieldDidBeginEditing: method. Clicking directly on the UITextField doesn't bubble up so it can't be handled in one place.
Coocoo4Cocoa
You should have the UITextFieldDelegate methods call the tableView:didSelectRowAtIndexPath: if the scrollng in both cases is the same. This is the only reasonable way to do it, since the UITableView is obscured by the UITextField.
Matt Gallagher
A: 

Register for UIKeyboardWillShowNotification and UIKeyboardWillHideNotification, then adjust your view as necessary in the notification handlers. One of the example apps shows how to do this, but I forget which...SQLiteBooks, or maybe EditableDetailView.

Brandon Fosdick
+2  A: 

There are a couple of ways to fix this issue. What happens is that the tableViewCell delegates the touch event to its subviews which causes the textfield to handle the touch in stead of your cell.

To fix this:

  • Set the UITextfield's userinteractionEnabled property to NO, then when you get the didSelectRowAtIndexPath message you re-enable userInteractionEnabled and call the TextField's becomeFirstResponder. On v2.2 you don't even need to set the userInteractionEnabled flag, I have not tested this with other versions however the documentation is quite clear that you should have this enabled. in the tableViewController you simply need to have the indexpath saved until you get the UIKeyboardDidShow message

  • Create a delegate for the UITextField that reports back to your tableViewController so that you can set the scrolling offset from there.

  • register for the keyboard events and then figure out the scrolloffset by checking what textfield is in editing mode

A: 

I was struggling with this same issue, where I have UITextFields inside of UITableViewCells and couldn't get view to scroll to the field when it was being edited. The core of my solution is below.

The key to this code is the line where the UITextField is created. Instead of hard coding a x and y value in the CGRectMake() function, it uses the x and y from the cell in which its being placed (+/- any offset you want from the edges of the cell as shown below). Hard coding x and y values in the UITextField* gives every cell the same x,y frame position for every UITextField* (it apparently is overridden by the cells frame when its displayed) so when you invoke the 'scrollRectToVisible' code it doesn't seem to have the correct coordinates to which it should scroll.

1) create cell, and add UITextField* to the cell using cell's frame x and y values (I'm including offsets here which are optional

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

 UITableViewCell* cell;
 cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
 cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"UITableViewCell"] autorelease]; 

 //this is the critical part: make sure your UITextField* frame is based on the frame of the cell in which it's being placed.
 UITextField* txtField = [[UITextField alloc] initWithFrame:CGRectMake(cell.frame.origin.x+20, cell.frame.origin.y+9, 280, 31)];
 txtField.delegate = self;

 [cell addSubview:txtField];
 return cell;
}

2) adjust scroll view in textFieldDidBeginEditing

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

 CGRect textFieldRect = [textField frame];
 [self.tableView scrollRectToVisible:textFieldRect animated:YES];
}
Unless I'm missing something, this just scrolls to the top of the table whenever you select a cell. Also, previous entries dissappear if you scroll away from them.
cannyboy
+1  A: 

I did not find any solutions that work for me in the web. After days of Googling and experimenting, I finally have this issued well nailed. It is a complex bug in Apple iPhone as you will see in the end of this post.

If you ran into an issue like me as follows:

  1. having tableviewcell larger than half of the iphone screen (Do not confused with Apple's UICatalog's examples have a short tableview cell of less than 50 points, not applicable here.),

  2. having more than one uitexfields in the cell or combination of uitextfield and uitextview or uiwebview in the cell,

  3. Tapping between uitextfields and uitextview or uiwebview results in unpredictable scroll position either the clicked uitextfield jumps out of view or covered by the keybaord. It only works the very first time when the keyboard appears in the tableviewcell and not working right subsequently.

I had the major break through after reading posts similar to this one: http://alanduncan.net/old/index.php?q=node/13 They did not get it completely right either. The pain is caused by a bug in UIKeyboard events. When the keyboard first appear, it issue an UIKeyboardWillShowNotification and UIKeybaordDidShowNotification. Theree is a bug in iPhone that somehow the first UIKeyboardWillShowNotification differs from the subsequent UIKeyboardWillShowNotification. The solution is to OBSERVE UIKeyboardDidShowNotification. So when your cell will appear, add the following code

 NSNotificationCenter*nc=[NSNotificationCenter defaultCenter];
    [nc addObserver:self selectorselector(keyboardDidShow name:UIKeyboardDidShowNotification object:self.window];

In the keyboardDidShow function, we need to scroll the TABLEVIEW, not the tableviewcell as suggested in above post. Or you may see various objects go separate way, not scroll together in one piece.

(void)keyboardDidShow:(NSNotification *)notif
{
    //1. see which field is calling the keyboard
    CGRect frame;
    if([textField_no1 isFirstResponder])
    frame=textField_no1.frame;
    else if([textField_no2 isFirstResponder])
    frame=textField_no2.frame;
    else if([textField_no3 isFirstResponder])
    frame=textField_no3.frame;
    else if([textView isFirstResponder])
    frame=textView.frame;
    else return;
    CGRect rect=self.superview.frame;

    //2. figure out how many pixles to scroll up or down to the posistion set by theKeyBoardShowUpHorizon.

    //remove the complexity when the tableview has an offset
    [((UITableView*)[self.superview).setContentOffset:CGPointMake(0,0) animated:YES];

    int pixelsToMove=rect.origin.y+ frame.origin.y-theKeyBoardShowUpHorizon;

    //3. move the uitableview, not uitableviewcell
    [self moveViewUpOrDownByPixels:pixelsToMove];

}

- (void)moveViewUpOrDownByPixels:(int)pixels
{

   [UIView beginAnimations:nil context:NULL];
   [UIView setAnimationDuration:0.6];

   //find the position of the UITableView, the superView of this tableview cell.
   CGRect rect=self.superview.frame;

   //moves tableview up (when pixels >0) or down (when pixels <0)
   rect.origin.y -= pixels;
   rect.size.height += pixels;
   self.superview.frame = rect;
   [UIView commitAnimations];
}

To restore the tableView back, you need to add observer on UIKeyboardDidHideNotification (not UIKeyboardWillHideNotification as suggested by other posts, to avoid flickering) where you tableviewcell appears every time and put back the tableview to where it was.

[nc addObserver:self selectorselector(keyboarDidHide) name:UIKeyboardDidHideNotification object:nil];

- (void)keyboardDidHideNSNotification*)notif
{
    //we have moved the tableview by number of pixels reflected in (self.superview.frame.origin.y). We need to move it back
    [self moveViewUpOrDownByPixels:self.superview.frame.origin.y];
}

Do not forget to remove both of the observesr when your cell disappear by [[NSNotificationCenter defaultCenter] removeObserver:...

That is all it takes. I hope Apple iPhone team one day will resolve this issue, maybe in 4.0 in a few months.

Wayne Lo
A: 

Hi, I've found a solution.

  1. Open .xib file in interface builder.
  2. Select the table view
  3. From IB Menu select Tools->Size Inspector On Scroll View Size Section, modify Inset -> Bottom value to 100, 150 ,250 depending how big is your table view. 4.

    -(void) textFieldDidBeginEditing:(UITextField *)textField { UITableViewCell *cell = (UITableViewCell *) [[textField superview] superview]; [self.tableView scrollToRowAtIndexPath:[tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionBottom animated:YES];

}

Andi