Table cell as the delegate of the text field inside it? - iphone

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;
}

Related

iPhone:How to manage UITextfield delegate methods on dynamic number of customcells

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.

UITextView inside UITableView

I know this question has been asked before, though I can't seem to find what I want. I have a section in my app where I have a tableview with a textview inside of it. I DO NOT want to have a seperate .xib, .h, and .m files for the tableview cell. The tableview does not need to shrink or grow depending on the amount of text inside the textview. I don't want the textview to be editable either. I hope this isn't too much to ask for, though I'm really stuck at the moment.
To do this, you will need to embed one in your UITableViewCell. But there's no need to create a custom cell. Here is the basic idea of what you will want to do:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UITextView *comment = [[UITextView alloc] initWithFrame:CGRectMake(cell.frame.origin.x, cell.frame.origin.y, cell.frame.size.width, tableView.rowHeight)];
comment.editable = NO;
comment.delegate = self;
[cell.contentView addSubview:comment];
[comment release];
}
return cell;
}
You will, of course, need to set your rowHeight if you don't want the standard 44pt height that comes with the cell. And if you want actual cells, you'll need to add your own logic so that only the cell you want is a textView, but this is the basic idea. The rest is yours to customize to your fitting. Hope this helps
EDIT: to bypass the textView to get to your cell, there are two ways to go about this.
1) you can make a custom textView class and overwrite touchesBegan to send the message to super:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
}
this will send the touch events to its superview, which would be your tableView. Considering you didn't want to make custom UITableViewCells, I imagine you probably don't want to make a custom textView class either. Which leads me to option two.
2) when creating the textView, remove comment.editable = NO;. We need to keep it editable, but will fix that in a delegate method.
In your code, you will want to insert a textView delegate method and we'll do all our work from there:
EDIT: changing this code to use with a UITableViewController
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
// this method is called every time you touch in the textView, provided it's editable;
NSIndexPath *indexPath = [self.tableView indexPathForCell:textView.superview.superview];
// i know that looks a bit obscure, but calling superview the first time finds the contentView of your cell;
// calling it the second time returns the cell it's held in, which we can retrieve an index path from;
// this is the edited part;
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
// this programmatically selects the cell you've called behind the textView;
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
// this selects the cell under the textView;
return NO; // specifies you don't want to edit the textView;
}
If that's not what you wanted, just let me know and we'll get you sorted out

UITextField in UITableViewCell Help

I have scoured the internet looking for a good tutorial or posting about having a UITableView populated with a UITextField in each cell for data entry.
I want to keep track of each UITextField and the text written within it while scrolling. The tableView will be sectioned. I have been using a custom UITableViewCell but I'm open to any method.
Also, is it possible to use the textFields as ivars?
If any of you could point me in the right direction, it would be greatly appreciated.
Thank you in advance!
To solve your problem you have to maintain an array, with some number (number of textFields you added to all cells) of objects.
While creating that array you need add empty NSString objects to that array. And each time while loading the cell you have to replace the respected object to respected textField.
Check the following code.
- (void)viewDidLoad{
textFieldValuesArray = [[NSMutableArray alloc]init];
for(int i=0; i<numberofRows*numberofSections; i++){
[textFieldValuesArray addObject:#""];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return numberofSections;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return numberofRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
CustomTextField *tf = [[CustomTextField alloc] initWithFrame:CGRectMake(5,5,290,34)];
tf.tag = 1;
[cell.contentView addSubView:tf];
[tf release];
}
CustomTextField *tf = (CustomTextField*)[cell viewWithTag:1];
tf.index = numberofSections*indexPath.section+indexPath.row;
tf.text = [textFieldValuesArray objectAtIndex:tf.index];
return cell;
}
- (void)textFieldDidEndEditing:(UITextField *)textField{
int index = textField.index;
[textFieldValuesArray replaceObjectAtIndex:index withObject:textField.text];
}
First of all, you must understand that UITableViewCell and UITextField are just views, they are not supposed to hold data, they are just supposed to display them and allow the user to interact with them: The data should remain stored in the controller of the table view.
You have to remember that UITableView allows you to reuse UITableViewCell instances for performance purpose: what's displayed on the screen are actually the only subviews UITableView keep there. It means that you'll reuse one cell that already has a text field in it and set the text on that field directly. When the user will tap on the field it will edit it and you'll have to get the value back from it when the user will have finished.
The fastest way, would be to use what Satya proposes, that is building normal UITableViewCell and insert into a UITextField (there's no need for a CustomTextField class...). The tag will allow you to get back to the text field easily... But you'll have to setup your text field so it behaves properly when the table view resizes or if a label in the same cell changes.
The cleanest way to do that is to subclass UITableViewCell and setup the layout of your label and text field, and you can provide the text field as a property of the custom subclass.
I have used Textfields in tableview for data entry.
I have customised the UITextField class in a separate class called Utility :
In Utility.h
#interface CustomUITextField:UITextField{
NSInteger rowNumber;
}
In Utility.m
#implementation CustomUITextField
#synthesize rowNumber;
#end
My tableView cellForRowAtIndexPath method is
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *Identifier = #"Cell";
UITableViewCell *cell = [theTableView dequeueReusableCellWithIdentifier:Identifier];
if(cell == nil)
cell = [self reuseTableViewCellWithIdentifier:Identifier withIndexPath:indexPath];
CustomUITextField *itemNameTextField = (CustomUITextField *)[cell.contentView viewWithTag:TEXTFIELD_TAG];//this is the tag I have set in reuseTableViewCellWithIdentifier method for textfield
itemNameTextField.rowNumber = indexPath.row;
itemNameTextField.text = #"";//you can set it for the value you want
if(itemListTable.editing)
itemNameTextField.borderStyle = UITextBorderStyleRoundedRect;
else
itemNameTextField.borderStyle = UITextBorderStyleNone;
return cell;
}
You can customise the delegate methods of UITextField for CustomUITextField & can save the text entered in a particular row's textfield by accessing the CustomTextField's row number.
Just try with this.
I had the same problem here is some code i found that treats this problem . it puts the data enterd in a Array Look at the Debugger console to see the results of the text being typed here's the link TextFieldCell. . Happy Codeing

How to populate a label field from a selected row in a uitableview

I have a uitableview that is populated from a sqlite query.
I want to select or click on a row and then display that row's value in a uilabel field. To show the user that the row was selected.
I also want to pass that value on to different controllers that will be called later.
Here is a copy of my cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"psystem";
PSystem *psystem = [self.ppdm_systems objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell...
// self.accessoryType = UITableViewCellAccessoryCheckmark;
cell.textLabel.text = psystem.system_id;
return cell;
}
I took out the _label.text .... in my various experiments.
Now what is not working is the passing of the value to different controllers.
Using the example listed here, the source controller is TableViewController and is where the value is set. The target controller is DetailViewController.
I can pass the title of the tab bar in, but that's from TableView --> DetailView.
I am not sure how to pull from tableview; ie: Tableview <-- DetailView when I am in DetailView.
thx
In your UIViewController, implement:
- (MyObject *)valueForSelectedRow {
MyCell *cell = (MyCell *)[self.tableView cellForRowAtIndexPath:[self.tableView indexPathForSelectedRow]];
return cell.myObject;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Get value
MyObject *object = [self valueForSelectedRow];
// Update the label, assumed that _label is a pointer to a UILabel view object.
_label.text = object.myValue;
}
When you want to push a new view controller, you just call -valueForSelectedRow and then use that value to push the controller.
This is assumed that you have a UITableViewCell subclass, with a property set to some model object. When you don't have that and just set the text property, that NSString object will be your 'model' object, although it would be easier when your cells handle custom model objects.
EDIT: Thanks for editing your answer. I now have the information I need. In this line: cell.textLabel.text = psystem.system_id, you setup the cell by simply setting the textLabel's text property. This is what I described in the paragraph above. I always create a UITableViewCell subclass, with a property set the the complete PSystem object. When you assign a PSystem object to the cell, it will handle it's contents, so you can easily manage your view in the, well, view. That's a very compelled approach since you never have to look at the controller again to alter the view's contents.
However, it can be done the way you currently have it. It would look something like:
- (NSString *)valueForSelectedRow {
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[self.tableView indexPathForSelectedRow]];
return cell.textLabel.text;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Get value
NSString *value = [self valueForSelectedRow];
// Update the label, assumed that _label is a pointer to a UILabel view object.
_label.text = value;
}
In this case, your PSystem model has been replaced with an NSString object. For this, it's enough, but it could be so much easier to have the object itself. Okay, that can also be done by selecting the PSystem object again from the p_system array by the NSIndexPath, but things will become harder once you come up with more complex tableviews.

iphone tableview cells with custom textview - get textview reference

I have a UITableView with 15 cells, each with a separate text box in it.
I have implemented UITextViewDelegate and I am able to received changed textview data using textViewDidChange (etc). But I have one big problem still, how do I know WHICH textview sent this, (i.e. in which cell was the textview altered?)
Its interesting to have so much working, yet not know precisely where it comes from.
A whole bunch of code is available if required.
Regards #norskben
Code
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
//Big Text Box
UITextView *detailLabel = [[UITextView alloc] initWithFrame:CGRectMake(30, 80, CONST_Cell_width, 150)];
detailLabel.tag = 20;
[cell.contentView addSubview:detailLabel];
}
UITextView * detailLabel = (UITextView *) [cell.contentView viewWithTag:20];
You can assign tags (integers) to the different views and query the tag number to see which view called the method. Look for the tag property on the view:
tag
The receiver’s tag, an integer that you can use to identify view objects in your application.
#property(nonatomic) NSInteger tag
see here
Not at my development machine, but when you create the UITextView you should be able to assign it a tag. I think it is [myTextView setTag:x]; where x is an integer.
Then, in the TextViewDidChange use
if (textview.tag == x) {
//do something
} else if (textview.tag == y) {
//do something else and so on
}
Hope that helps a little.
The text views pass a reference to themselves in every delegate method so you know which one sent it. To make a connection to the cell, I'd set each text view's tag property to a different value that corresponds to the row of the cell they're in.
Here's an important question: Are your text boxes static, or can they change over time? If they won't change (the user can't alter the number of cells or add more later), then you can declare a new textField for each cell. I have something similar in my apps. I have two text boxes, and depending on which textField is currently active, the delegate does something different.
Declare separate text fields in your header
UITextField *textField1;
UITextField *textField2;
UITextField *textField3;
in the delegate method, use if statement blocks to find out which textField is changing:
if (textField == textField1) {
//do something
} else if (textField == myTextField2) {
//something else
}
Note that this really only works if your view is static.
Hope this helps
Have a great day
When you're searching the UITableView's cells for the event source UITextView, only iterate over the cells that the user can currently see. This can be obtained using the following UITableView method:
- (NSArray *)visibleCells