dismiss iPhone keyPad in dynamic UITableView - iphone

I have UITableView with two sections. First section is a static row with stepper which creates cells of second section. Each cell of second section contains the UITextField with keypad. I can dismiss the keypad using UITapGestureRecognizer or additional DONE button in keypad but it is working for the last cell only.
I have tried the following methods:
UITapGestureRecognizer in the table view
in my ViewDidLoad I put:
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(hideKeyboard)];
[self.tableView addGestureRecognizer:gestureRecognizer];
and then
-(void)hideKeyboard{
[self.tableView resignFirstResponder];
}
or
-(void)hideKeyboard:(UITapGestureRecognizer*)sender{
[self.cellText endEditing:YES];
}
Use tags to recognize which textfield I am editing.
In
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath I added
[cellText addTarget:self action:#selector(myNumberValueBeginEditing:) forControlEvents:UIControlEventEditingDidBegin];
and in
-(void)myNumberValueBeginEditing:(UITextField *)sender
{
int row = [sender.superview.superview tag];
UITextField *cellTemp = (UITextField*)[(UITableViewCell *)sender.superview viewWithTag:200+row];
cellTemp.delegate = self;
[cellTemp becomeFirstResponder];
}
then I am trying to resignFirstResponder in DONE button
-(IBAction)doneButton:(UITextField *)sender {
NSLog(#"doneButton");
int row = [sender.superview.superview tag];
[(UITextField*)[(UITableViewCell *)sender.superview viewWithTag:200+row] resignFirstResponder];
}
I have no more ideas how to resign the keypad from all UITextFields. If anyone has some remedy, I will really appreciate.

You were close with your use of endEditing:. Instead of sending endEditing: to an instance of your text field, try sending it to your main view. e.x:
[self.view endEditing:YES];
endEditing: can be sent directly to a text field instance, or to a view, in the case of the latter any text field that is editing that is a subview of the view you specified will resign first responder.
From the docs:
Causes the view (or one of its embedded text fields) to resign the
first responder status

Related

UITableViewCell setEditing:animated doesn't get called if cell is the first responder and is offscreen

I have a subclass of UITableViewCell with added UITextField to edit the contents of a cell in editing mode.
In my custom cells implementation I have overridden setEditing like this:
-(void)setEditing:(BOOL)editing animated:(BOOL)animated
{
if ([self.textField isFirstResponder])
[self.textField resignFirstResponder];
NSLog(#"%#",self.textLabel.text);
if (editing) {
self.textLabel.hidden = YES;
self.textField.hidden = NO;
}else{
self.textLabel.hidden = NO;
self.textField.hidden = YES;
}
[super setEditing:editing animated:animated];
}
And what happens is when I call setEditing for first time they all go to editing mode. But if I try to modify cell and if this cell goes offscreen and I tap the "Done" button the cell is still in editing mode. Only the cell that has gone offscreen. If it's visible onscreen when I tap the "Done" button it just works.
Here is a video to better describe the problem: video on Dropbox
You can solve this in your UITableViewController subclass by implementing the following:
- (void)setEditing:(BOOL)editing animated:(BOOL)animated{
[super setEditing:editing animated:animated];
//since setEditing isn't called on cells that are offscreen do this to ensure the keyboard is dismissed.
[self.view endEditing:editing];
}
You may try to dismiss the keyboard when the textfield goes off screen

Labels with targets to another view

I would like to have a login similar to this screenshot:
The problem is that I don't know how to do the bottom, these two options. When I push, I'd like to put another view — the sign up view or reset password view —, but I don't know how to do these elements (are they labels?).
They could be UIButton with the type Custom and with a value for the text:
To make this, First you take a UILabel to show the "Tumblr" option. Then you create a UITableView. This TableView would contain 2 sections like "Email" and "Password". Make the edges of the UITableView as rounded using
TableView.layer.cornerRadius = 10;
Now to push to another view you can simply write any data in the UITableViewCells in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
and using the
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
you can pass that information to the next view for the reset password option you mentioned likewise. Create a UIButton and name it as "Login".
I this is what you wanted to achieve ?? Any doubts please tell. Thanks :)
EDIT:
For the options below what you can do is that make the UIButtons as custom and write their text as "Reset Password" etc. Then on their click you can open a presentModalViewController of each of the next view's or in the same view itself, in which you would be able to do your sign in and reset stuff. Hope it helps !!!
It is a label and you link it with the action method.
//using UITapGestureRecognizer to easy to set target to another view
UITapGestureRecognizer *tab_1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(action_1)];
tab_1.delegate = self;
[label1 addGestureRecognizer: tab_1];
UITapGestureRecognizer *tab_2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(action_2)];
tab_2.delegate = self;
[label2 addGestureRecognizer: tab_2];
-(void)action_1{
//your action or view;
}
-(void)action_2{
//your action or view;
}

Hide Keyboard when user taps outside the text field in UITableView and UIScrollView

My UIViewController hierarchy is as follows
UIView
UIScrollView
UITableView
UITableViewCell
UITextField
The UITableView is added to the view controller programmatically.
I want to hide keyboard when user taps outside UTTextField either on the view or on the UITableView
I am executing some methods when user taps on other UITableView rows
I tried
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
UIScrollView doesn't send the touch events.
I tried adding Tap gesture
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[singleTap setNumberOfTapsRequired:1];
[[self view] addGestureRecognizer:singleTap];
but with TapGesture, hides the following event
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
are there any other possible ways to hide the keyboard?
use the code : [self.view endEditing:YES];
use the UITextFieldDelegate
and the method
– textFieldShouldEndEditing:(UITextField*) txtField
{
[txtField resignKeyPads];
return YES:
}
this can also done by the scrolview delgate too
-(void) scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//resign all keypads of all textfields use array containing keypads
}
one thing more is change the class of UIView to UIControl and make a method IBAction and connect the UIControl touchupInside to that ibaction, it will resign keypads
If you want to still use tap gestures you need to add the gesture recogniser to the table background like so:
[tableView.backgroundView addGestureRecognizer:singleTap];
This will prevent the hiding of:
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
If you want to put a gesture recognizer on the background view you need to make sure it has one.
Add
self.tableView.backgroundView = [[UIView alloc] initWithFrame:self.tableView.bounds];
UITableView didSelectRowAtIndexPath will not call when UITableview is Edit Mode. So you suppose to create custom gesture event to handle the same.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//cell design code goes here.
UITapGestureRecognizer *doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTap:)];
doubleTapGestureRecognizer.numberOfTapsRequired = 1;
//tapGestureRecognizer.delegate = self;
[cell addGestureRecognizer:doubleTapGestureRecognizer];
return cell;
}
//Handle the click event
-(void) handleDoubleTap:(UITapGestureRecognizer*)sender{
[self.view endEditing:YES];
UITableViewCell * cell =(UITableViewCell*) sender.view;
//get the selected table indexpath.
NSIndexPath * indexPath= [tblCart indexPathForCell:cell]; //to handle the scroll
tblCart scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
NSLog(#"Comming");
}

UITable Cell not selectable where there is a UITextView in the cell

I've added a UITextView to my cell. If the userclicks on the cell where the UITextView then then didSelectRowAtIndexPath: is not called unless they click the area where the UITextView is not covering. Is there a work around or what is it I have done wrong?
UITextView *txtview = [[UITextView alloc] initWithFrame:CGRectMake(75, 1, 250, 34)];//init and create the UIWebView
txtview.autoresizesSubviews = NO;
//txtview.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
[txtview setBackgroundColor:[UIColor grayColor]];
[txtview setFont:[UIFont fontWithName:#"Helvetica" size:15]];
txtview.textColor = [UIColor blackColor];
txtview.scrollEnabled = NO;
[txtview setOpaque:NO];
//[txtview setDelegate:self];
txtview.editable = NO;
txtview.text = aBlogRss.title;
[txtview setContentInset:UIEdgeInsetsMake(-11,-8,0,0)];
//[txtview loadHTMLString:htmlString baseURL:nil];
[cell addSubview:txtview];
[txtview release];
Many Thanks,
-Code
I think the solution is actually
txtView.userInteractionEnabled = NO;
This will pass touches to the parent view.. or in this case the UITableViewCell. If you are doing this in multiple places it would be a good idea to subclass UITAbleViewCell.
Alternatively, you could make your class a UITextViewDelegate, set your txtView.delegate to self, and implement
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView ,
and then select the proper UITableViewCell through self.tableview.. But that would be nothing short of a hack.
You should create your UITextView in viewDidLoad: and only keep [cell addSubview:txtview]; in your cellForRowAtIndexPath:.
Alternatively, you can use: [cell setAccessoryView: txtView];
Another thing, how are you creating your cell?
Is the cell used once or potentially unlimited number of times? If once, then you can use
- (void)selectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition
and manually insert the indexPath since you know where it lies.
If the cell is to be re-used, try setting the "tag" property of the textfield with the row, then when the touch is detected by the UITextView, use one of its delegate methods to call the above UITableView method, providing an NSIndexPath derived from the UITextView's tag.
Add an UITapGestureRecognizer to the cells.
Write a gesture handling code like below.
- (IBAction)handleTap:(UITapGestureRecognizer *)sender
{
[self.tableView selectRowAtIndexPath:
[self.tableView indexPathForCell:(UITableViewCell *)sender.view]
animated:NO
scrollPosition:UITableViewScrollPositionNone];
}
Connect them.
You would obtain both selectable UITextView and selectable UITextViewCell.
Yes, it makes sense that the row does not get selected as there is a textView over it. Here are a couple of ways of going about this.
You can make the textView frame such that you provide room for selecting the row.
You can set each textView (for each row) as a property and find out which textView was selected. Based on that you can call the textViewDidBeginEditing method and programmatically make that row selectable.
[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
References: How do I select a UITableViewCell by default?
Select tableview row programmatically
Note: You will have to logically link each textView with the it's corresponding cellIndexPath.
try
txtView.userInteractionEnabled = YES;
That should do it.

Clicking on UITextField in a UITableViewCell

I have an issue where when a textField is clicked on in a UITableViewCell, 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?
I found the following works well (It assumes you're in a table view controller)
- (void)textFieldDidBeginEditing:(UITextField *)textField{
CGPoint pnt = [self.tableView convertPoint:textField.bounds.origin fromView:textField];
NSIndexPath* path = [self.tableView indexPathForRowAtPoint:pnt];
[self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
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
You can set your controller as the delegate of your UITextField, then adjust your table view in either textFieldDidBeginEditing: or textFieldShouldBeginEditing:
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:
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.),
having more than one uitexfields in the cell or combination of uitextfield and uitextview or uiwebview in the cell,
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.
I discovered that it's actually pretty easy to do this.
The UITextField delegate method textFieldDidBeginEditing will give you the text field, which you can then map to an indexPath using:
self.currentIndexPath = [self.tableView indexPathForRowAtPoint:textField.frame.origin];
Then you can scroll the cell into view (i.e. in your UIKeyboardDidShowNotification keyboard notification handler):
[self.tableView scrollToRowAtIndexPath:self.currentIndexPath atScrollPosition:UITableViewScrollPositionNone animated:YES];
I've found a solution.
Open .xib file in interface builder.
Select the table view
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.
Code
-(void) textFieldDidBeginEditing:(UITextField *)textField
{
UITableViewCell *cell = (UITableViewCell *) [[textField superview] superview];
[self.tableView scrollToRowAtIndexPath:[tableView indexPathForCell:cell]
atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
didSelectRowAtIndexPath won't be called for UITextField embedded cells; hence, scroll logic needs to be elsewhere.
- (void)textFieldDidBeginEditing:(UITextField *)textField {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:1];
UITableViewCell *cell = [_tableView cellForRowAtIndexPath:indexPath];
[_tableView setContentOffset:CGPointMake(0, cell.frame.size.height) animated:YES];
}
Make sure to wire textField delegate to self
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.
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];
}
The problem is aggravated by the fact that there is no simple way to find out whether user tapped on text field or it was activated via becomeFirstResponder.
The most elegant solution I could come up with was to implement a hitTest:withEvent: on cell subclass and basically pretend that text field does not exist until cell is selected.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *view = [super hitTest:point withEvent:event];
if(view == self.textField && !self.selected) {
return self;
}
return view;
}
tableView:didSelectRowAtIndexPath: then should manually make text field a first responder.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
TextFieldCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
[cell.textField becomeFirstResponder]
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
Finally, we have to deselect the row when we finish editing. This can be done via UITextField delegate or via keyboard notification, whatever you prefer.
- (void)textFieldDidEndEditing:(UITextField *)textField {
[self.view endEditing:YES];
}
we have one controller called TPKeyboardAvoiding, it handled everything about dynamic auto scrolling for tableview and scrollview.
you can download sample code from below code.
https://github.com/NarayanaRao35/TPKeyboardAvoiding