I am developing an app that has a UITextView within a custom UITableViewCell in a tableview. The tableviewcell has several gesture recognizers. My problem is that the textview is responding to touches before the tableViewCell's recognizers. I have a long tap for moving the cell to another location but instead the textview will try and select it's text for copy/paste/magnifying glass functions. Also, the textview is swallowing touches from the tableview itself and so scrolling will not function within the tableview if you begin the scroll touching the textview.
even with the editable property set to false the textview still wants to select text and show the magnifying glass.
Initially I had everything working using a UITextField instead of a UITextView but I need support for multiple lines of text.
So how can I keep the textview from swallowing any touch event? Any suggestions or thoughts would be greatly appreciated.
Here's how we handle UITextView user interaction that is contained within a UITableViewCell:
1) Your UIViewController should conform to UITableViewDataSource, UITableViewDelegate and UITextViewDelegate :
#import <UIKit/UIKit.h>
#interace MyExampleController : UIViewController <UITableViewDataSource, UITableViewDelegate, UITextViewDelegate>
2) Initially, the text view's userInteractionEnabled property is set to NO
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *textViewCellIdentifier = #"MyTextViewCellIdentifier";
MyTextViewViewCell *cell = [tableView dequeueReusableCellWithIdentifier:textViewCellIdentifier];
if (!cell)
{
// ... do your stuff to create the cell...
cell.textView.userInteractionEnabled = NO;
cell.textView.delegate = self;
}
// do whatever else to set the cell text, etc you need...
return cell;
}
3) Check if a text view cell was tapped via UITableViewDelegate method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
BOOL isTextViewCell = ... // do your check here to determine if this cell has a text view
if (isTextViewCell)
{
[[(MyTextTableViewCell *)cell textView] setUserInteractionEnabled:YES];
[[(MyTextTableViewCell *)cell textView] becomeFirstResponder];
}
else
{
// ... do whatever else you do...
}
}
4) Check for \n to determine when to have the textView resign first responder (passed when user presses the return key):
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if ([text rangeOfString:#"\n"].location != NSNotFound)
{
[textView resignFirstResponder];
textView.
return NO;
}
return YES;
}
5) Save text into your model once after the text view has resigned (ends editing):
- (void)textViewDidEndEditing:(UITextView *)textView
{
NSString *text = textView.text;
// do your saving here
}
This was mostly written on the spot, so there may be some minor errors in there, but hopefully you get the general idea.
Good luck.
Related
I need to get the the currently selected UITableViewCell as its tapped. So upon my finger touching the screen/cell I want to run a method from which I can say something as simple as:
selectedCell = cell;
cell being the one I just tapped and selectedCell being a copy I store.
I am using a custom subclassed UITableViewCell which is why I think I'm having trouble.
Just implement setHighlighted:animated: method on your own custom tableview cell like this.
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
[super setHighlighted:highlighted animated:animated];
NSLog (#"setHighlighted:%# animated:%#", (highlighted?#"YES":#"NO"), (animated?#"YES":#"NO"));
}
TouchDown
- setSelected:animated: is called on the cell itself on touch down here, you can inform a cells delegate
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[self.delegate willSelectCell:self];
}
declare custom cells delegate as property of the cell
#property id<MyCellDelegate> delegate;
TouchUP
save the cell in the delegate
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
_selectedCell = [aTableView cellForRowAtIndexPath:indexPath];
}
just pay attention to the fact that Cell Views can be reused
I have dynamic number of textfields in my tableview, I put each textfield into a customcell in IB and load the cells by nibName.
I want to validate and show alert as user enters data, also when editingisDone I want to get the input value from user and save it to the relavent object.
for instance these are some delegate methods I can use:
- (void)textFieldDidEndEditing:(UITextField *)textField{
//save the data
}
- (IBAction)textFieldDoneEditing:(id)sender {
//hide the keypad when done is pressed
[sender resignFirstResponder];
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange{}
2 questions:
1-When getting user input and validating the input how will I know which textfield's delegate is fired since there are dynamic numbers of cells and textfields, and how can I manage this?
2-For hiding the keyboard I did this but not sure this is correct;
-In IB I opened the customcell-->right click uitextfield and connect its didEndonExit to FirstResponder's textFieldDoneEditing method. This works but I can't return if I didnt add any chars to textfield. so it forces to write something in order to press the button.
With regards to your first question ...
In the following code I'll assume you have one UITextField in each cell. I'll also assume you've created an UITableViewCell subclass called CustomCell which contains an UITextField.
#pragma mark - UITableViewDataSource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault identifier:CellIdentifier] autorelease];
cell.textField.tag = indexPath.row;
cell.textField.delegate = self;
}
return cell;
}
#pragma mark - UITextFieldDelegate
- (void)textFieldDidEndEditing:(UITextField *)textField
{
NSLog(#"textField tag: %d", textField.tag); // this will show which textField did end editing ...
}
Regarding your second question; if I understand your problem correctly, unchecking "Auto-enable Return Key" in the textfield's properties in IB should allow you to press the return button even when it's empty. I tested this on a simple textfield in a UIView, but it should work in your case.
I unfortunately still have not seen the light when it comes to organising my iphone app nicely into controllers and views. Let me illustrate with an example:
I am working on a sign up page which consists of a table view with a list of custom table cells. Some of these cells have a text field inside them and when the user touches one of those a keyboard slides up from the bottom. The keyboard has a return key in its lower right corner and when the user hits this key I would like the keyboard to slide down again.
Now, where do I put the
- (BOOL) textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
? Currently I have made my custom table cell conform to the text field delegate protocol and have put the method in there, but it does seem a bit wrong to have stuff like that inside a view class? On the other hand I do not find it appropriate in the table view controller either.
you can set your table view controller as the text field's delegate...
just remove the code in the custom cell where you set it as the delegate and instead set the delegate in the table view controller's cellForRowAtIndexPath method where you actually create and return the cell..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
MyCustomCell *myCell = (MyCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (myCell == nil)
{
myCell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellSelectionStyleNone reuseIdentifier:CellIdentifier] autorelease];
myCell.myTextField.delegate = self;
}
//other cell specific code goes here
return myCell;
}
In my iPhone project I'm using a UITableview with UITableViewCells containing UITextfields. I have seen in many apps that it is possible to use a next button to jump to the next textfield in the next cell. What is the best way to accomplish this?
My idea is to get the indexPath of the cell with the textfield that is being editing and then get the next cell by cellForRowAtIndexPath. But how can I get the indexPath of the cell I'm currently editing?
Thanks!
Keep references to the UITextField instances in your table view.
Assign unique tag values to your UITextField instances.
In your last text field, you might set its Return key type, which changes the keyboard's Return key label from "Next" to "Done": [finalTextField setReturnKeyType:UIReturnKeyDone];
In the UITextField delegate method -textFieldShouldReturn:, walk through the responders:
- (BOOL) textFieldShouldReturn:(UITextField *)tf {
switch (tf.tag) {
case firstTextFieldTag:
[secondTextField becomeFirstResponder];
break;
case secondTextFieldTag:
[thirdTextField becomeFirstResponder];
break;
// etc.
default:
[tf resignFirstResponder];
break;
}
return YES;
}
Assuming the UITextField was added to the UITableViewCell like below
UITableViewCell *cell;
UITextField *textField;
...
textField.tag = kTAG_TEXTFIELD;
[cell.contentView addSubview:textField];
...
You can get the current index path via
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
if([textField.superView.superView isKindOfClass:[UITableViewCell class]]) {
UITableViewCell *cell = (UITableViewCell *)textField.superView.superView;
NSIndexPath *indexPath = [self.myTableView indexPathForCell:cell];
}
...
The next row's UITextField would then be
NSIndexPath *indexPathNextRow = [NSIndexPath indexPathForRow:(indexPath.row+1) inSection:indexPath.section];
UITableViewCell *cellNextRow = (UITableViewCell *)[self.myTableView cellForRowAtIndexPath:indexPathNextRow];
UITextField *textFieldNextRow = (UITextField *)[cellNextRow.contentView viewWithTag:kTAG_TEXTFIELD];
Hope it helps!
I want to edit the user's username inside a UITableView. I added a UITextField to the UITableViewCell and this seems to work very nicely. But when the user touches the cell (even outside the textfield), he expects to edit.
How do I programatically select the textfield?
The code would look something like:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
userName.selected = TRUE;
}
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cellSelected = [tableView cellForRowAtIndexPath: indexPath];
UITextField *textField = [[cellSelected.contentView subviews] objectAtIndex: 0];
[textField becomeFirstResponder];
[tableView deselectRowAtIndexPath: indexPath animated: NO];
}
This assumes that you have no quicker way to know which UITextField object is in which cell, and that you know for sure that the UITextField will be the first subview.
You also might want to put in a check for [textField isFirstResponder] -- no point in making it the firstResponder if it already is. This may not be necessary though.