In my app rows are added to my TableView from a different view. When the user adds the rows the user is taken back to the TableView. The problem is that the text that was previously entered is no longer shown.
I am able to load it with an NSMutableDictionary but the user cannot see it. Any ideas on what I should do? what code I should add and where I should add it? Thanks a lot!
Here is code from a tableview method. I think the fix will go in here somewhere.
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
static NSString *CellIdentifier = #"Cell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.wtf = [[UITextField alloc]init];
NSUInteger count =0;
for (NSMutableDictionary *search in dataForAllRows){ //this just helps me pull the right data out of an array of NSMutableDictionary's
if ([search valueForKey:#"indexSection"] == [NSNumber numberWithInteger:(indexPath.section -1)]) {
if ([search valueForKey:#"indexRow"] == [NSNumber numberWithInteger:indexPath.row]) {
NSMutableDictionary *match = [dataForAllRows objectAtIndex:count];
[cell.wtf setText:[match objectForKey:#"wtf"]];
NSLog(#"%#",cell.wtf.text); // this outputs the correct value in the command line
}
}
count++;
}
}
}
Here is the code for my CustomCell.m
#import "CustomCell.h"
#implementation CustomCell
#synthesize wtf, cellPath;
- (void)awakeFromNib {
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
-(void)layoutSubviews{
wtf = [[UITextField alloc] initWithFrame:CGRectMake(7, 3, 65, self.contentView.bounds.size.height-6)];
self.wtf.delegate = self;
[wtf setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
[wtf setAutocorrectionType:UITextAutocorrectionTypeNo];
[wtf setAutocapitalizationType:UITextAutocapitalizationTypeNone];
[wtf setBorderStyle:UITextBorderStyleRoundedRect];
wtf.textAlignment = NSTextAlignmentCenter;
wtf.keyboardType = UIKeyboardTypeNumberPad; //
[wtf setAutocapitalizationType:UITextAutocapitalizationTypeWords];
[wtf setPlaceholder:#"enter"];
[self.contentView addSubview:wtf];
}
Consider defining the cell with identifier #"Cell" in IB as a prototype row of the table. Then, use dequeueReusableCellWithIdentifier:forIndexPath: to retrieve the cell in cellForRowAtIndexPath. It's easier to understand what your cells will look like, and you can avoid some mistakes that are common when defining subviews in code.
Speaking of common mistakes, your code appears to present a couple: it doesn't frame the text field, nor does it add it as a subview of the cell. Both would explain not seeing the text field.
#williamb's advice is correct and necessary: only build the cell's subview's if they are absent, but the building of the cell is incomplete...
if (cell == nil) {
cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UITextField *wtf = [[UITextField alloc]initWithFrame:CGRectMake(10,10,200,42];
[wtf setDelegate:self];
[cell addSubview:wtf];
cell.wtf = wtf;
}
As I mentioned in comment, a sectioned table ought to be supported by a 2D array. The outer array is an array of sections. Each section array is an array of dictionaries equal to the ones you're searching each time through this method, but pre-arranged so all that's done in cellForRowAtIndexPath is indexing into an array:
NSDictionary *d = self.myCorrectlyStructuredModel[indexPath.section][indexPath.row];
cell.wtf.text = d[#"wtf"];
It's not a big challenge to build this from what you have. Consider doing this right after you solve the text field problem. I (or others) can give you some advice -- if you need any -- about how to build that structure.
It looks like you are only setting the text value of your textfield if that cell does not exist and overriding your textfield instance to one that does not have a frame as #danh mentioned. What I believe you want to do is reuse the textfield once it is added to your cell's contentview and change what that textfield shows for each index path.
Try refactoring your cell code to be more like:
#implementation ExerciseCell
#pragma mark - Init
- (id)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style
reuseIdentifier:reuseIdentifier];
if (self)
{
wtf = [[UITextField alloc] initWithFrame:CGRectMake(7, 3, 65, 44)];
wtf.delegate = self;
[wtf setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
[wtf setAutocorrectionType:UITextAutocorrectionTypeNo];
[wtf setAutocapitalizationType:UITextAutocapitalizationTypeNone];
[wtf setBorderStyle:UITextBorderStyleRoundedRect];
wtf.textAlignment = NSTextAlignmentCenter;
wtf.keyboardType = UIKeyboardTypeNumberPad;
[wtf setAutocapitalizationType:UITextAutocapitalizationTypeWords];
[wtf setPlaceholder:#"enter"];
[self.contentView addSubview:wtf];
}
return self;
}
and your tableview datasource class to be more like
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
static NSString *CellIdentifier = #"Cell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
[cell.wtf setDelegate:self];
}
NSUInteger count = 0;
for (NSMutableDictionary *search in dataForAllRows){ //this just helps me pull the right data out of an array of NSMutableDictionary's
if ([search valueForKey:#"indexSection"] == [NSNumber numberWithInteger:(indexPath.section -1)]) {
if ([search valueForKey:#"indexRow"] == [NSNumber numberWithInteger:indexPath.row]) {
NSMutableDictionary *match = [dataForAllRows objectAtIndex:count];
[cell.wtf setText:[match objectForKey:#"wtf"]];
NSLog(#"%#",cell.wtf.text); // this outputs the correct value in the command line
}
}
count++;
}
}
}
Also do you mean to assign the the textField's delegate twice? Once in the cell and once in the tableview's datasource?
In order to load text into the UITextField in the CustomCell I added the following method
CustomCell.m
-(void)viewMyCellData{
//here I can set text to my textfield
wtf.text = #"Desired Text"; //this will read in every wtf textfield in the table
//getting the right text from an array will be asked in another question that I will post
//in a comment to this answer
}
Next we call this using [self viewMyCellData]
at the end of our
-(void)layoutSubviews method which is also in CustomCell.m
Related
I have a tableView cell with a UITextField to enter the text.
I am populating the tableView with the following code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Ingredient Cell";
IngredientsTableViewCell *ingredientCell = [self.ingredientsTableView dequeueReusableCellWithIdentifier:cellIdentifier];
// NSManagedObjectContext *managedObject = [self.ingredientItems objectAtIndex:indexPath.row];
if (ingredientCell == nil)
{
ingredientCell = [[IngredientsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
ingredientCell.accessoryType = UITableViewCellAccessoryNone;
[ingredientCell addSubview:ingredientCell.ingredientTextField];
[ingredientCell.ingredientTextField addTarget:self action:#selector(editingChanged:) forControlEvents:UIControlEventEditingChanged];
}
//Populate the textfield in the ingredientCell
ingredientCell.ingredientTextField.text = [self.ingredientItems objectAtIndex:indexPath.row];
return ingredientCell;
}
Following is the #selector(editingChanged:) method for the textField which never executes. What am I doing wrong?
-(void) editingChanged:(id)sender{
NSLog(#"hi");
// get the text being entered
NSString *ingredientText = ((UITextField *)sender).text;
//get the index of the selected row
NSInteger selectedIndex = [self.ingredientsTableView indexPathForSelectedRow].row;
//save the text to the array
[self.ingredientItems setObject:ingredientText atIndexedSubscript:selectedIndex];
}
So you'll want to use the textFieldDelegate (or if you're adventurous you could use ReactiveCocoa).
Add this at the top
<UITextFieldDelegate>
And this in your cellForRowAtIndexPath
ingredientCell.ingredientTextField.delegate = self;
ingredientCell.ingredientTextField.tag = 1;
And this delegate method
//Use this method instead of addTarget:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if (textField.tag == 1){
//do some stuff
}
}
see this stack overflow post: iOS - Adding Target/Action for UITextField Inside Custom UITableViewCell
But you might have a slightly different problem as well. This line of code seems redundant:
[ingredientCell addSubview:ingredientCell.ingredientTextField];
You're ingredient cell seems like it should already have the ingredientTextField as a subview. This might cause you problems as well. You can add it as a subview in a xib that's attached to your ingredientsTableViewCell class, or simply add it in code as
[self addSubview:ingredientTextField]
Hope that helps.
if (ingredientCell == nil)
{
ingredientCell = [[IngredientsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
ingredientCell.accessoryType = UITableViewCellAccessoryNone;
[ingredientCell addSubview:ingredientCell.ingredientTextField];
[ingredientCell.ingredientTextField addTarget:self action:#selector(editingChanged:) forControlEvents:UIControlEventEditingChanged];
}
this portion looks much of problems
try taking out this line from if statement
[ingredientCell.ingredientTextField addTarget:self action:#selector(editingChanged:) forControlEvents:UIControlEventEditingChanged];
This will help you.
You can add this line in cellForRowAtIndexPath and add UITextFieldDelegate in Viewcontroller.h file
ingredientCell.ingredientTextField.delegate = self;
[ingredientCell.ingredientTextField addTarget:self action:#selector(editingChanged:) forControlEvents:UIControlEventEditingChanged];
This is textfield controller event
UIControlEventEditingDidBegin = 1 << 16, // UITextField
UIControlEventEditingChanged = 1 << 17,
UIControlEventEditingDidEnd = 1 << 18,
UIControlEventEditingDidEndOnExit = 1 << 19, // 'return key' ending editing
I created a custom UITableViewCell class that embedded a UITextfield to each cell, in the addItemTableViewController, I want to get text values within all UITextField-embededd cells and create a new model object, but I'm running into a problem:
cellForRowAtIndexPath returns nil for invisible cells, after I scrolled down to the buttom of my tableview then hit the Add button, the first a few rows' textField text value became null.
Is there anyway I can fix this? I've been Googlging for hours and still not find a answer for it.
Here's my addItemTableViewController code:
- (IBAction)doneAdd:(UIBarButtonItem *)sender {
[self.delegate addItem:[self newItem]];
}
- (NSMutableArray *)newItem
{
NSMutableArray *newItem = [[NSMutableArray alloc] init];
for (int i = 0; i < [_appDelegate.title count]; i ++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
UPFEditableUITableViewCell *cell = (UPFEditableUITableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
NSLog(#"%#", cell.editField.text);
//[newItem addObject:cell.editField.text]; //this does not work as null cannot be added into a array
}
NSLog(#"%#", newItem);
return newItem;
}
Here's my custom UITableViewCell class implementation
#import "UPFEditableUITableViewCell.h"
#implementation UPFEditableUITableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.editField = [[UITextField alloc] initWithFrame:CGRectZero];
[self.contentView addSubview:self.editField];
}
return self;
}
- (void)layoutSubviews
{
if ([self.detailTextLabel.text length] == 0) {
self.detailTextLabel.text = #" ";
}
[super layoutSubviews];
// place the edit field in the same place as the detail text field, give max width
self.editField.frame = CGRectMake(self.detailTextLabel.frame.origin.x, self.detailTextLabel.frame.origin.y, self.contentView.frame.size.width-self.detailTextLabel.frame.origin.x, self.detailTextLabel.frame.size.height);
}
- (void)showEditingField:(BOOL)show
{
self.detailTextLabel.hidden = YES;
self.editField.text = self.detailTextLabel.text;
}
#end
I think made a fundamental mistake, have my view talks with the model layer, what a lesson learned...
anyway, I managed to work out a solution, in short, here's what I did:
made cell as the delegate of the UITextField
implemented textFieldDidChange, to capture textField changes, once there's a change, submit the changed content to the model
And here's the code:
in the cellForRowAtIndex:
[cell.editField addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
cell.editField.delegate = self;
and here's the code for the textFieldDidChange:
- (void)textFieldDidChange :(UITextField *)theTextField
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
[self.item removeObjectAtIndex:indexPath.row];
[self.item insertObject:theTextField.text atIndex:indexPath.row];
}
This is not a problem.The cell are dequeud and reused whenever new cells are created.Hence while scrolling the tableview at the top they become null and the new cells are created with the same identifier.
For your problem you will need to store the value of textfield's value into a dictionary.For this you will need to save it at the time you are dequeing the cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellReuseIdentifier = #"cellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellReuseIdentifier];
}else{
NSLog(#"text is %#",cell.textLabel.text);
for (UIView *v in cell.contentView.subviews) {
if ([v isKindOfClass:[UITextField class]]) {
UITextField *textField = (UITextField *)v;
[myDictionary setObject:textField.text forKey:indexPath]; // declare myDictionary in the interface first.This will also prevent the values from duplicating
NSLog(#"%#",myDictionary);
}
}
}
return cell;
}
To get value from UITextField you can set the delegate on your ViewController. Then you should implement textField:shouldChangeCharactersInRange:replacementString: where you can update NSString value.
The second solution might be keeping reference to the each cell in NSMutableArray.
Anyway you try to avoid calling cellForRowAtIndexPath: from table view controller.
You should always try to save the data in model classes and use the array of these model class instances to load the table. So that you don't need the tableCells to get the data after that. The datas are always to be fetched from models and not the UIs (TableCells in this case).
You might be loading the tablecell initially using an arra,y. If so, use that array to create the model class objects you mentioned instead of the tablecells.
I have a UITableView with 10 cells.Except the first cell, all are the same.
Around 3 cells are displayed on screen at a time. Each cell has a label which says "Claim". Depending on certain events, I change the "claim" in SOME cells to "claimed".
Problem is when I scroll the cells , the some other cells (whose "claim" I haven't changed to "claimed") also show as "claimed". This seems random and feel is due to cell reuse and poor implementation. Please review the code and help me approach this better.
My requirement is :
Display 10 cells out of which all are identical except the first one.
All identical cells have a button / label with text "claim"
When I press the button , "claim" should change to "Claimed" ONLY for that particular cell in which the button resides.
This change should persist event when I scroll.
Custom cell used is :
#import "CustomSaloonCell.h"
#implementation CustomSaloonCell
#synthesize claimButton;
#synthesize delegateListener;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.claimButton=[UIButton buttonWithType:UIButtonTypeSystem];
self.claimButton.frame=CGRectMake(30,140,80, 30);
[self.claimButton setTitle:#"claim" forState:UIControlStateNormal];
[self.claimButton setTitleColor:[UIColor purpleColor] forState:UIControlStateNormal];
self.claimButton.titleLabel.font = [UIFont fontWithName:#"Arial" size:(22)];
[self.claimButton addTarget:self action:#selector(claimButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:self.claimButton];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)claimButtonPressed{
[self.delegateListener didClickedClaimButton:self];
}
#end
The cell creation function :
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row==0){
CustomHeaderCell *headerCell = [[CustomHeaderCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"header_cell"];
headerCell.selectionStyle = UITableViewCellSelectionStyleNone;
return headerCell;
}
static NSString *cellIdentifier = #"HistoryCell";
// Similar to UITableViewCell, but
CustomSaloonCell *cell = (CustomSaloonCell *)[theTableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[CustomSaloonCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.claimButton.tag = indexPath.row+TAG_OFFSET;
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"salon.jpg"]];
cell.delegateListener = self;
return cell;
}
The delegate method which modifies the label is :
- (void) claimConfirmedDelegate:(NSInteger)tag{
CustomSaloonCell *selectedCell=(CustomSaloonCell*)[self.claimTableView cellForRowAtIndexPath: [NSIndexPath indexPathForRow:(tag-TAG_OFFSET)inSection:0]];
[selectedCell.claimButton setTitle:#"claimed" forState:UIControlStateNormal];
}
Save state of button (also title if your required) in separate instance mutable array.
When you pressed button and calling delegate method add that cell indexpath in your buttonStateArray.
Now check current indexPath in cellForRowAtIndexPath method: is containing buttonStateArray. If it present then change your button state and title yeah other thing if you want.
It will work after scrolling too.
Declare NSMutableArray *buttonStateArray; in .h file of tableview class.
Allocate it on initialization or after view loading.
- (void) claimConfirmedDelegate:(NSInteger)tag{
CustomSaloonCell *selectedCell=(CustomSaloonCell*)[self.claimTableView cellForRowAtIndexPath: [NSIndexPath indexPathForRow:(tag-TAG_OFFSET)inSection:0]];
[selectedCell.claimButton setTitle:#"claimed" forState:UIControlStateNormal];
[buttonStateArray addObject:[NSIndexPath indexPathForRow:(tag-TAG_OFFSET)inSection:0]];
}
Now in cellForRowAtIndexPath: method
for (NSIndexPath *selectedIndex in buttonStateArray){
if([selectedIndex isEqual:indexPath]){
//Change your state of button.
}
}
I have seen every post that is close to this question, and still not finding something useful. I have textFields in every cell that is being used as a form for the user to fill out. Everything with the cells works fine except when scrolling, the input in the textFields disappears when the cell scrolls off screen. I know this is because of dequeue. But there should be a way to save the data entered so that it doesn't disappear when scrolling or exiting the app. I also want to be able to take this info and email it as a PDF, or document. What is the best way to achieve this? The code below is an example of how I am generating my cells etc.
.h file
#interface MasterViewController : UITableViewController <UITextFieldDelegate, UITextFieldDelegate, UITableViewDataSource, UINavigationBarDelegate>{
NSString* name_;
UITextField* nameFieldTextField;
}
// Creates a textfield with the specified text and placeholder text
-(UITextField*) makeTextField: (NSString*)text
placeholder: (NSString*)placeholder;
// Handles UIControlEventEditingDidEndOnExit
- (IBAction)textFieldFinished:(id)sender;
#property (nonatomic,copy) NSString* name;
.m file
#synthesize name = name_;
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
self.name = #"";
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
// Make cell unselectable and set font.
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.font = [UIFont fontWithName:#"ArialMT" size:13];
if (indexPath.section == 0) {
UITextField* tf = nil;
switch ( indexPath.row ) {
case 0: {
cell.textLabel.text = #"Name" ;
tf = nameFieldTextField = [self makeTextField:self.name placeholder:#"John Appleseed"];
nameFieldTextField.tag = 1;
[cell addSubview:nameFieldTextField];
break ;
}
// Textfield dimensions
tf.frame = CGRectMake(120, 12, 170, 30);
// Workaround to dismiss keyboard when Done/Return is tapped
[tf addTarget:self action:#selector(textFieldFinished:) forControlEvents:UIControlEventEditingDidEndOnExit];
}
return cell;
}
// Textfield value changed, store the new value.
- (void)textFieldDidEndEditing:(UITextField *)textField {
//Section 1.
if ( textField == nameFieldTextField ) {
self.name = textField.text ;
}
}
- (void)viewWillAppear:(BOOL)animated{
NSString *nameCellString = [[NSUserDefaults standardUserDefaults] stringForKey:#"nameCellString"];
nameFieldTextField.text = nameCellString;
}
- (void)viewWillDisappear:(BOOL)animated{
NSString *nameCellString = self.name;
[[NSUserDefaults standardUserDefaults] setObject:nameCellString forKey:#"nameCellString"];
}
There are actually two problems here, both of them being in your cellForRowAtIndexPath: implementation.
You are putting the text field into the cell, even if this cell is reused and already has a text field. Thus you are actually piling text field over text field, covering up the previously existing text field.
You are not putting the text back into the text field if there was already text in the text field for that row (index path).
In other words, the cells are (as you rightly say) reused, so it is up to you to take that fact into account. You must look at the state of the incoming cell, and reconfigure the cell accordingly.
First off, I urge you to consider creating a custom cell in a storyboard, and grabbing that. It's a lot easier than coding one, and I think it's the future. That said, look into populating your tableViews with NSArrays, instead of hard-coding strings into the cellForRowAtIndexPath method. I've taken the liberty of giving you an example of this.
The following is based on your code, and should be a copy/paste solution. Look it over, and see how it operates.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *titlesArray = #[#"Name", #"Birthday", #"Favorite Food"];
UITableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:[NSString stringWithFormat:#"%i%i", indexPath.section, indexPath.row]];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
// Make cell unselectable and set font.
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.font = [UIFont fontWithName:#"ArialMT" size:13];
// Populate label from array
cell.textLabel.text = titlesArray[indexPath.row];
if (indexPath.section == 0) {
UITextField* tf = nil;
switch ( indexPath.row ) {
case 0: {
tf = nameFieldTextField = [self makeTextField:self.name placeholder:#"John Appleseed"];
nameFieldTextField.tag = 1;
[cell addSubview:nameFieldTextField];
break ;
}
// Textfield dimensions
tf.frame = CGRectMake(120, 12, 170, 30);
// Workaround to dismiss keyboard when Done/Return is tapped
[tf addTarget:self action:#selector(textFieldFinished:) forControlEvents:UIControlEventEditingDidEndOnExit];
}
// Set the reuse identifier to a unique string, based on placement in table
// This ensures that the textField will retain its text
cell.reuseIdentifier = [NSString stringWithFormat:#"%i%i", indexPath.section, indexPath.row];
}
return cell;
}
// Textfield value changed, store the new value.
- (void)textFieldDidEndEditing:(UITextField *)textField {
//Section 1.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
switch (textField.tag) {
case 1:
[defaults setObject:textField.text forKey:#"nameCellString"];
self.name = textField.text;
break;
default:
break;
}
[defaults synchronize];
}
EDIT: Changed to accommodate more cells.
You should use array of UIDictionary for your tableDataSourceArray Like:
step1)
NSArray *tableDataSourceArray = [[NSArray alloc]init];
NSMutableDictionary *cellData = [[NSMutableDictionary alloc]init];
[cellData setValue:#"" forKey:#"Name"];
...//so on
[tableDataSourceArray addObject:cellData];
cellData = nil;
repeat step1 as number of records you have.
Now in cellForRowAtIndexPath:
nameFieldTextField.tag = indexPath.row; //To store index of dataSourceArray
nameFieldTextField.text = [[tableDataSourceArray objectAtIndex:indexPath.row] valueForKey:#"Name"];
And at last in textFieldDidEndEditing:
NSMutableDictionary *cellDataDic = tableDataSourceArray objectAtIndex:textField.tag];
[cellDataDic setValue:textField.text forKey:#"Name"];
hope it will help you.
I think the easiest way to fix your problem is to create a new class for your cell (inherit from UITableViewCell) and add new property like customerTextField (UITextField). In constructor add new textfield but with CGRectZero. In method layoutSubviews you will assign CGRect for your textfield.
Generally speaking this approach will make your UIViewController cleaner (you will reduce number of checks for textfield state).
I made a custom UITableViewCell in Interface Builder (Storyboard) and imported it to my project via #import CustomTableViewCell.h.
Everything works fine, but the cell is only loaded in selected state.
I want the cell to be loaded in every row by init.
P.S. The slider and text field connections work fine. I also made all of the IB Connections.
CustomTableViewCell.m
#import "CustomTableViewCell.h"
#implementation CustomTableViewCell
#synthesize sliderLabel, slider;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (IBAction)getSliderValuesWithValue:(UISlider *)sender
{
sliderLabel.text = [NSString stringWithFormat:#"%i / 100", (int) roundf(sender.value)];
}
#end
Further Code
- (CustomTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Kriterium";
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.textLabel.text = [NSString stringWithFormat:#"%#", [listOfItems objectAtIndex:indexPath.row]];
return cell;
}
P.S. If I add some Buttons etc. programmatically in the above method it works. But I want to design the rows in IB. There has to be a solution.
Okay ... strange things happening here ... ;-) The problem was this line:
cell.textLabel.text = [NSString stringWithFormat:#"%#", [listOfItems objectAtIndex:indexPath.row]];
Leaving it out did the trick. I had to add another UILabel to my CustomCell which I fill with text.
CONCLUSION
Filling the standard UITableViewCell.textLabel.text seems to overwrite the PrototypeCells.
... too much customization hurts. ;-)
Thanks anyway! :)
Suggesting you to not go for IB. Just define those controls as property and in your init method- initWithStyle(CustomTableViewCell.m file) initialize UISlider with its default property:
UISlider *tempSlider = [[UISlider alloc] initWithFrame:frame];
tempSlider.selected = NO;
//define other properties as well
self.slider = tempSlider;
[self addSubview:self.slider];
[tempSlider release];
Besides you can also set cell selection style to none.
cell.selectionStyle = UITableViewCellSelectionStyleNone;