How to get the Dynamic tableview cell data.
I have a table view like this. All the cells are creating dynamically.
I want to get all the text (flavor and %)data when submit button is pressed.
The problem was I creating text in dynamically. So I cannot individually identify the text box. How could get the data from dynamic text box?
Set tag to your uitextfield in your custom cell
For eg.
cell.lblFlavour.tag = indexPath.row;
cell.lblPercent.tag = indexPath.row;
Now, access your uitextfield on the basis of your indexPath
Use tag property to identify each UI component uniquely. Assign the same tag property where you are creating textFields and button to each row then after change tag value for next row and get them using code.
To set tag:
self.yourTextfield.tag = 100;
self.yourbutton.tag = 100;
// set action method to uibutton
[cell.yourButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
To get the UI components using tag property:
-(IBAction)buttonPressed:(id)sender{
// here get all ui component using tag
UIButton *button = (UIButton *)sender;
NSLog(#"%d", [button tag]);
}
or you can use method didSelectRowAtIndexPath to get values see code:
- (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSLog(#"getting index path %#",indexPath);
NSLog(#"getting index path %#",cell.yourTextField.text);
}
You can set tag to your textfield and by that tag you can access them.
For example,
UITextField *textField = [[UITextField alloc]initWithFrame:CGRectMake(0, 0, 200, 30)];
textField.tag = 100; //set tag
UITextField *textField1 = (UITextField*)[self.view viewWithTag:100]; //retreive by tag
So, like this you can manage your dynamically made textfields.
Update :
then set two tag 100 and 101 respectively. Now you have to got cell first and from that cell you can got your textfields so on button's click first got all cell, then you can got textfield from that cell like :
UITextField *textField = (UITextField*)[cell viewWithTag:100];
So, you have to got cell first in your button's click.
The main idea of UITableView is store data into data source, not into cell. When you tap "+" button on the navigation bar, you should add new item into array and then call [tableView reloadData]. So a UITableView just represent data from array. And when submit button will pressed you just enumerate an array of data source and get all the text from each row.
When you tap text into text field inside the cell, you could use delegates or blocks to store data into array.
try below code :
When you click on submit button
for (int i=0; i < [[tableView visibleCells] count]; i++)
{
//yourArrayname is the number of rows in the UITableView /Or UITableView visible cells
NSIndexPath *indexPath = [NSIndexPath indexPathForRow: i inSection: 0];
CustomTableViewCell *cell = [tblExperience cellForRowAtIndexPath:indexPath];
for (UIView *view in cell.contentView.subviews){
if ([view isKindOfClass:[UITextField class]]){
UITextField* CurrentTextField = (UITextField *)view;
NSLog(#"val %d %#",i,CurrentTextField.text);
[finalArray addObject:CurrentTextField.text];
}
}
}
Assign dynamic tags to your textfields, implement textfield delegates and save the data in an array whenever textfield ends editing. Something like this
-(void)textFieldDidEndEditing:(UITextField *)textField {
[_array insertObject:textField.text atIndex:textField.tag];
}
Related
I put a tableview in my storyboard, and filled the cell with a button with "0" as the tag. I populated the tableview using an array. Let's just say I have 20 elements in my array, that makes it 20 cells on the tableview. This is the code I'm using to give tags to the button on each cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == _tblCart) {
static NSString *cellIdentifier = #"CartCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
UIButton *btn = (UIButton *)[cell viewWithTag:0];
[btn setTag:indexPath.row];
[btn addTarget:self action:#selector(logTag:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
return nil;
}
I thought my code will work just fine, but actually there is something wrong. On cell 0-5, the button tag is correct. On the following cell the tag will reset again to 0. What am I doing wrong?
There is also another logic problem here, you are reusing table cells, some of which you've changed the tag of the button to something other than 0. So if you get a reused tablecell, there will come a time that the UIButton won't have a tag of zero and therefore you won't be able to change it correctly.
Don't set 0 as a tag identifier to views.
All UIViews have a tag by default 0.
So
[cell viewWithTag:0];
probably will return the contentView of the cell.
Both Flexicoder and l0gg3r are correct. Also, relying on button's tag as row identifier is a bit of a clunky workaround in my opinion. Consider this approach:
- (void)logTag:(UIButton *)sender {
NSIndexPath *indexPath = [_tblCart indexPathForRowAtPoint:[_tblCart convertPoint:sender.center fromView:sender]];
// do your stuff knowing which indexPath the button belongs to
}
In cellForRowAtIndexPath I do the following:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
UITextField *texfield = (UITextField *)[cell viewWithTag:1];
if (indexPath.section < [self.SmsDataArray count]) {
SmsModel * smsObj = self.SmsDataArray[indexPath.section];
texfield.text = smsObj.phoneNumber;
}
texfield.tag = 10000;
return cell;
I am not able to populate the textfield if I change the tag.
If i comment out texfield.tag = 10000; the textfield gets populated as expected, what do I need to fix here?
Basically I need to assign the tags to the textfield because the cells are dynamic.
If you're not using the standard cell, then you should subclass UITableViewCell, and a create a property to point to your text field so you don't need to use –viewWithTag: to get a pointer to it. Then, in –tableView:cellForRowAtIndexPath:, you can assign a tag based on the indexPath.row.
Problem -- You are overwriting the textfield tag. With the first call tag is changed to 10000.
But this method gets called for the same cell again, it searches textfield having tag 1. But there is no such textfield.
Solution -- Use any substitute of this line
(UITextField *)[cell viewWithTag:1];
for this
you can use custom cell and access textfield as "cell.textfield"
Or make custom textfield in cellForRowAtIndex(). And set its tag to indexpath.row
I have a NSTimer that calls this method every fourth second:
- (void)timerDecrement
{
timerCount = timerCount-1;
[OtherViewControllerAccess updateTimeLeftLabel];
}
In the updateTimeLeftLabel in the other class:
- (void)updateTimeLeftLabel
{
int timeLeft = OtherClassAccess.timerCount;
UILabel *timeLeftLabel = [[UILabel alloc] initWithFrame:CGRectMake(200, 10, 120, 20)];
timeLeftLabel.text = [NSString stringWithFormat:#"Tid kvar: %ih", timeLeft];
[cell addSubview:timeLeftLabel];
}
Basically I want my app to update a label in a cell in the tableview with the current time left, but the above method doesn't do anything to the call. So my question is, how can I add this subview to the cell outside the cellForRowAtIndexPath:delegate method, and then make it update that label every time the method is called.
So my question is, how can I add this subview to the cell outside the
cellForRowAtIndexPath:delegate method, and then make it update that
label every time the method is called.
The answer is, don't add subviews to a table view cell outside of cellForRowAtIndexPath. The cells belong to the table view, and you absolutely, categorically, should NOT try to modify them. That's the table view's job.
Just as a small example of what's wrong with your code, you would be adding an ever-increasing number of label views to your table view cell, one every 1/4 second. That's bad.
Second point: Which cell is "cell"? A table view manages a whole table of cells. If the user scrolls, some cells are scrolled off-screen and replaced with different cells.
Instead, you should figure out which indexPath contains the cell with your data in it, change the data in your model, and tell your table view to update the cell at the appropriate indexPath. That will cause it to redraw with updated contents.
Here is how I did something similar. I created a custom UITableViewCell class that has a timestamp UILabel:
#property (nonatomic) UILabel *labelTimestamp;
In that cell's layoutSubviews, I update the label size based on its title.
- (void)layoutSubviews {
[super layoutSubviews];
[self.labelTimestamp sizeToFit];
...
}
I then have an NSTimer firing every minute in my UIViewController that update that label in every visible cell (you could adapt to update only one cell with a specific indexPath).
- (void)timerDidFire
{
NSArray *visibleCells = [self.tableView visibleCells];
for (GroupViewCell *cell in visibleCells) {
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
[cell.labelTimestamp setText:[self.groupController statusUpdateDateAtIndexPath:indexPath]];
[cell setNeedsLayout];
}
}
I would keep the set up of the cell's centralized in cellForRowAtIndexPath: method. You can keep using your NSTimer to call reloadRowsAtIndexPaths:withRowAnimation: with the indexes of the cell/cells you want to update and therefore cellForRowAtIndexPath: will be called again.
Why don't you put that value (which you want to display in the cell) in a variable and assign a UILabel that value. In your updateTimeLeftLabel just call [self.tableView reloadData].
You can reload whole table or some specific rows but that needs connection of datasource with your views . You have to change your dataset first and then you have to call
[self.tableview reloadData];
another method is that, after changing dataset call
[self.tableview reloadRowsAtIndexPaths:indexPath withAnimation:animation];
2nd method requires indexPath i.e. you know that which cell you need to edit .
My problem was same . In my project there were 2 TextFields and 1 label in each cell . Now depending on the values of 2 textfields, I have to show their multiplication in UILabel. and this is my code.
-(void)textFieldDidChange:(id)sender{
UITextField *_sender = (UITextField *)sender;
int tag = _sender.tag;
int row = tag / 3;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
((UILabel *)[[self.tableView cellForRowAtIndexPath:indexPath] viewWithTag:row * 3 + 2]).text = #"hello";
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"here");
static NSString *CellIdentifier = #"procedureDetailsCell";
UITableViewCell *cell = (procedureCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if ( cell == nil ) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[((procedureCell *)cell).Quantity setTag:indexPath.row + 0];
[((procedureCell *)cell).Quantity addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[((procedureCell *)cell).Cost setTag:indexPath.row + 1];
[((procedureCell *)cell).Cost addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[((procedureCell *)cell).total setTag:indexPath.row + 2];
return cell;
}
Logic is simple I have used Custom TableViewCell which contains 2 textfields and 1 label. when one of the two textfield's value is changed we are calling "textFieldDidChange" method which finds indexpath and then find UITableViewcell and then updates its lastview's text value, that is our UILabel. we have to give unique tag to each of our views .
I am working on an iOS application where a button is enabled only after all UITextFields that are filled in (i.e. have at least one character inside each one). Each UITextField is in a custom UITableViewCell inside of a UITableView. Once the user has entered a value in each UITextField, I need the button to be enabled. Inside my viewDidLoad method, I disable the button as follows:
[_doneButton setEnabled:NO];
and then I have the following method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
for (int i = 0; i < [self.table numberOfSections]; i++) {
NSInteger rows = [self.table numberOfRowsInSection:i];
for (int row = 0; row < rows; row++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:i];
SimpleTableCell *cell = (SimpleTableCell *)[self.table cellForRowAtIndexPath:indexPath];
for (UIView *subView in cell.subviews) {
if ([subView isKindOfClass:[UITextField class]]) {
//Does not come to this point
UITextField *txtField = (UITextField *)subView;
if([[txtField text] length] > 0) {
//Enable button and bold title
[_doneButton setEnabled:YES];
[_doneButton.titleLabel setFont:[UIFont boldSystemFontOfSize:28]];
}
else {
[_doneButton setEnabled:NO];
}
}
}
}
}
return YES;
}
Unfortunately, my code does not get into the "if" clause where I check to see if the custom cell has a subView of type UITextField, and because of that, the button is never enabled. For the record, "SimpleTableCell" is the name of my custom UITableViewCell class that I've created. My code appears to be correct, but I can't figure out why it is not functioning correctly. Can anyone see what it is I'm doing wrong?
I think I would go about this in a completely different way. I would create a mutable dictionary to hold the strings in the various text fields. Give the text fields tags, and use the tags (converted to NSNumbers) as the keys in the dictionary. Implement textFieldDidEndEditing:, and in that method get the string, check that it's not an empty string, and if not, do setObject:forKey: on the dictionary. After you set the value, check the count of the dictionary's allKeys property, and if it equals the number of text fields you have, enable the button.
That's because the only logical subview of the cell is an UIView containing all the items of the cell. It's property is "contentView".
The content view of a UITableViewCell object is the default superview for content displayed by the cell. If you want to customize cells by simply adding additional views, you should add them to the content view so they will be positioned appropriately as the cell transitions into and out of editing mode.
More information about it here: https://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewCell_Class/Reference/Reference.html#//apple_ref/occ/instp/UITableViewCell/contentView
Have you set the UITextField's delegate? If that method is not getting called at all, that is the problem.
I am using group of buttons with different images and tableview with custom cell in my project.every cell having group of components (like imageview,button,label,slider) when pressing each button one cell will be added.
My button image and also added to imageview of the cell.
How can i get the index of each cell when pressing the button again.
cell will be added when i press the button at first time.
when pressing second time i want to increment the label value inside the cell.so i need the indexpath to cell the cell from the tableview.
I'm not sure exactly what you're looking for, maybe you can clarify what you're trying to do.
The method indexPathForCell: is a UITableView method that gives you the index of a certain cell.
Clarify your question a bit and maybe we can help more.
You can call button touch event to get the cell of uitableview -
UIView *cellView = (UIVIew *)[button superview];
UITableViewCell *cell = (UITableViewCell *)[cellView superview];
NSIndexPath *indexPath = [self.tableview indexPathForCell:cell];
Without knowing the structure of your cells, table, or anything like that. this code will work.
-(NSIndexPath *) pathForButton:(UIbutton *) b {
UITableView *tv = nil;
UIView *superView = [b superview];
UIView *cell;
while(superview != nil && ![superview isKindOfClass:[UITableView class]]){
cell = superview;
superview = [superview superview];
}
if(superview != nil && cell != nil){
tv = (UITableView*)superview;
return [tv indexPathForCell:cell];
}
return nil;
}