I have created a UITextField in a UITableView. I type the data in and close the keyboard. However when I scroll down and hide the UITextField and then scroll back up again, the 'UITextField' data is duplicated as seen below:
Original Load of View:
Typed in Data:
After hidden textfield and then started editing again:
- (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];
}
if ([indexPath section] == 0) { // Email & Password Section
cell.textLabel.text = #"Subject";
} else {
cell.textLabel.text = #"Task";
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if ([indexPath section] == 0) {
UITextField *subject = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
subject.adjustsFontSizeToFitWidth = YES;
subject.textColor = [UIColor blackColor];
if ([indexPath row] == 0) {
subject.placeholder = #"Maths";
subject.keyboardType = UIKeyboardTypeEmailAddress;
subject.returnKeyType = UIReturnKeyNext;
}
subject.backgroundColor = [UIColor clearColor];
subject.autocorrectionType = UITextAutocorrectionTypeNo;
subject.autocapitalizationType = UITextAutocapitalizationTypeWords;
subject.tag = 0;
subject.clearButtonMode = UITextFieldViewModeNever;
[cell.contentView addSubview:subject];
} else {
UITextView *task = [[UITextView alloc] initWithFrame:CGRectMake(102, 0, 185, 40)];
task.text = #"fasfashfjasfhasfasdjhasgdgasdhjagshjdgashjdgahjsdghjasgasdashgdgjasd";
task.editable = NO;
task.scrollEnabled = NO;
task.userInteractionEnabled = NO;
task.textColor = [UIColor colorWithRed: 62.0/255.0 green: 85.0/255.0 blue:132.0/255.0 alpha:1.0];
task.backgroundColor = [UIColor clearColor];
}
return cell;
}
Like Richard said, cells are reused (that's what the identifier purpose is), and that's why you test in your tableView:cellForRowAtIndexPath: for a nil value returned by dequeueReusableCellWithIdentifier:.
If a cell already exists (ie. was allocated earlier) and is not displayed anymore, dequeueReusableCellWithIdentifier: will use this cell to display the content of the newly appearing cell.
What you are doing is adding your UITextView every time your cells are displayed and not created. So each time a cell is gets scrolled out of the screen and a new cell pops in, you append a new UITextView in the cell. You should add subviews only in the if (cell == nil) part of your method. As the content of your cells are rather different, I'd recommend using two distinct identifiers.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifierForSection0 = #"Cell0";
static NSString *CellIdentifierForSection1 = #"Cell1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: [indexPath section] == 0 ? CellIdentifierForSection0 : CellIdentifierForSection1];
if (cell == nil) {
if ([indexPath section] == 0) { // Email & Password Section
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifierForSection0];
cell.textLabel.text = #"Subject";
UITextField *subject = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
subject.adjustsFontSizeToFitWidth = YES;
subject.textColor = [UIColor blackColor];
if ([indexPath row] == 0) {
subject.placeholder = #"Maths";
subject.keyboardType = UIKeyboardTypeEmailAddress;
subject.returnKeyType = UIReturnKeyNext;
}
subject.backgroundColor = [UIColor clearColor];
subject.autocorrectionType = UITextAutocorrectionTypeNo;
subject.autocapitalizationType = UITextAutocapitalizationTypeWords;
subject.tag = 0;
subject.clearButtonMode = UITextFieldViewModeNever;
[cell.contentView addSubview:subject];
} else {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifierForSection1];
cell.textLabel.text = #"Task";
UITextView *task = [[UITextView alloc] initWithFrame:CGRectMake(102, 0, 185, 40)];
task.text = #"fasfashfjasfhasfasdjhasgdgasdhjagshjdgashjdgahjsdghjasgasdashgdgjasd";
task.editable = NO;
task.scrollEnabled = NO;
task.userInteractionEnabled = NO;
task.textColor = [UIColor colorWithRed: 62.0/255.0 green: 85.0/255.0 blue:132.0/255.0 alpha:1.0];
task.backgroundColor = [UIColor clearColor];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
Note that this code is mainly for example purpose, and could be greatly reducted. Moreover, you should use subclass(es) of UITableViewCell like Richard suggested, as it will help organizing your code and make it more reusable.
BUT do NOT use drawRect: to add subviews. This is unnecessary and will impact performances. drawRect: should only be used if you intend to make real drawing like with CoreAnimation or CoreGraphics. Adding subview should be done in initWithFrame: or initWithCoder: depending of your use of Interface Builder or not.
Remember cells get reused, therefore the subviews are added each time it's reused. If you're going to add subviews to a cell you're best off creating a subclass of UITableViewCell and adding the subviews in the drawRect: method of that subclass. That way the modifications are part of the cell and aren't added each time the cell is reused.
Related
In my app i am customised the UITableView Cell with four UITextViews. Whenever i added data to the tableview and reload it. The text in the UITableViewCell get override with the previous texts.
I tried different approaches but couldn't figure out what was the problem.
I am using TableView in View Controller.
Here is the Code i used in my table View cell?
if ( [tableView isEqual:self.tableActions])
{
//Setting the text empty
static NSString *CellIdentifier = #"ActionsIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
NSLog(#"Index Path %i",[indexPath row]);
ActionDetails *actiondetails = [actionArray objectAtIndex:[indexPath row]];
NSLog(#"Action Text %#",actiondetails.actions);
//Actions
actionText=[[UITextView alloc] initWithFrame:CGRectMake(10, 5, 230,30)];
actionText.font = [UIFont systemFontOfSize:17.0];
actionText.editable = NO;
actionText.textColor=[UIColor blackColor];
actionText.text = actiondetails.actions ;
actionText.userInteractionEnabled = NO;
actionText.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:actionText];
//Owner
ownerBy=[[UITextView alloc] initWithFrame:CGRectMake(230, 5, 230,30)];
ownerBy.font = [UIFont systemFontOfSize:17.0];
ownerBy.textColor=[UIColor blackColor];
ownerBy.textAlignment = UITextAlignmentCenter;
ownerBy.text = actiondetails.owner;
ownerBy.editable = NO;
ownerBy.userInteractionEnabled = NO;
ownerBy.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:ownerBy];
}
ScreenShot
Thanks for your help guys.
Much Appreciated.
This happened to me a other day, the solution that I came up with was removing all subview from the cell after creating the cell in the if statement.
if(cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
if ([cell.contentView subviews]){
for (UIView *subview in [cell.contentView subviews]) {
[subview removeFromSuperview];
}
}
Remove cell identifier of Tableview otherwise take Customcell for the Tableview..
Just simple try this way :
{
//Setting the text empty
static NSString *CellIdentifier = #"ActionsIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
**// if(cell == nil) // comment this line in your code ,its work
// {**
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
**// }**
NSLog(#"Index Path %i",[indexPath row]);
ActionDetails *actiondetails = [actionArray objectAtIndex:[indexPath row]];
NSLog(#"Action Text %#",actiondetails.actions);
//Actions
actionText=[[UITextView alloc] initWithFrame:CGRectMake(10, 5, 230,30)];
actionText.font = [UIFont systemFontOfSize:17.0];
actionText.editable = NO;
actionText.textColor=[UIColor blackColor];
actionText.text = actiondetails.actions ;
actionText.userInteractionEnabled = NO;
actionText.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:actionText];
//Owner
ownerBy=[[UITextView alloc] initWithFrame:CGRectMake(230, 5, 230,30)];
ownerBy.font = [UIFont systemFontOfSize:17.0];
ownerBy.textColor=[UIColor blackColor];
ownerBy.textAlignment = UITextAlignmentCenter;
ownerBy.text = actiondetails.owner;
ownerBy.editable = NO;
ownerBy.userInteractionEnabled = NO;
ownerBy.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:ownerBy];
}
You are reusing the cell. Reused cell already has UITextview added to it.So you are overriding on it.
You must shift all your code of creating and adding UITextView to.
If(cell==nil)
{
}
After which you only need to set the Text to UITextview.
when your view did appear write reload your table view.
-(void)viewDidAppear:(BOOL)animated {
[tableView reloadData];
}
change your cellForRowAtIndexPath method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"S%1dR%1d",indexPath.section,indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// your code
}
// your code
return cell;
}
for (id vw in [[cell contentView] subviews]) {
if ([vw isKindOfClass:[UILabel class]])
{
UILabel *label = (UILabel *)vw;
[label removeFromSuperview];
}
}
for (id vw in [cell subviews]) {
if ([vw isKindOfClass:[UILabel class]])
{
UILabel *label = (UILabel *)vw;
[label removeFromSuperview];
}
}
I am trying to implement UITableview based application. In my tableView their is 10 Section and each section having one row.
I want implement each section have Different type of ContentView(1-8 same ContentView 9th section Different ContentView). I did this code For that.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 10;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"Cell1";
static NSString *CellIdentifier2 = #"Cell2";
UITextField *textField;
UITextView *textView;
NSUInteger section=[indexPath section];
if(section == 9){
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
//UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(cell==nil){
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1]autorelease];
textView=[[UITextView alloc]initWithFrame:CGRectMake(5, 5, 290, 110)];
[textView setBackgroundColor:[UIColor scrollViewTexturedBackgroundColor
]];
[textView setTag:([indexPath section]+100)];
[cell.contentView addSubview:textView];
}else{
textView=(UITextView*)[cell.contentView viewWithTag:([indexPath section]+100)];
}
return cell;
}else {
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
// UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell==nil){
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2]autorelease];
textField=[[UITextField alloc]initWithFrame:CGRectMake(5, 5, 290, 50)];
[textField setBackgroundColor:[UIColor scrollViewTexturedBackgroundColor]];
[textField setTag:([indexPath section]+100)];
[cell.contentView addSubview:textField];
}else{
textField=(UITextField*)[cell.contentView viewWithTag:([indexPath section]+100)];
}
return cell;
}
return nil;
}
My problem are:
1. After type some thing in the UITextField/UITextView i am scrolling in the UITableView. that time all data in the UITableViewCell(UITextField/UITextView) was lose, except last cell data.
2. If i create cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Instead of
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
Data will repeating . How can i over come this problem?
This line:
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
Should never appear in your data source cellForRowAtIndexPath method.
Apart from that, your code is OK, except that you are not setting the text field value anywhere. You need a model (such as an array of strings for the 10 textfield values). This model should be updated when the textfields are edited, and in your method above you copy the value back out of the model and into the textfield's text property:
textfield.text = [self.modelArray objectAtIndex:indexPath.section];
The table pools and reuses cells in an unpredictable fashion, so that subview of a cell that just scrolled off the bottom might reappear next at the top, or might be disposed of.
This is why you saw it partially work. The cell's subviews work okay until their cell gets reused or unloaded, then things move to the wrong place or data disappears.
The solution is that your table's datasource needs to hold onto it's own data. This is usually an array representing your model. Your case is a little unusual because you are using the text controls in your table as inputs, rather than display, which is more typical.
I suggest doing it like this:
// in #interface
#property (nonatomic, retain) NSMutableArray *sections;
// in #implementation
#synthesize sections=_sections;
// at some point before the view appears
self.sections = [NSMutableArray array];
for (int i=0; i<10; i++) {
UIControl *textControl;
if (i<9) {
textControl=[[UITextView alloc]initWithFrame:CGRectMake(5, 5, 290, 110)];
} else {
textControl=[[UITextField alloc]initWithFrame:CGRectMake(5, 5, 290, 50)];
}
[textControl setBackgroundColor:[UIColor scrollViewTexturedBackgroundColor]];
[textControl setTag:i+100];
[sections addObject:textControl];
[textControl release];
}
Now your cellForRowAtIndexPath is a little simpler:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier1 = #"Cell1";
static NSString *CellIdentifier2 = #"Cell2";
NSUInteger section=[indexPath section];
if(section == 9) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(cell==nil) {
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1]autorelease];
}
} else {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell==nil) {
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2]autorelease];
}
}
// who knows what subview this cell has? it might not have one, or it might have the wrong one
// just clean it up to be certain
for (UIView *view in cell.subviews) {
[view removeFromSuperView];
}
// get the textControl we set up for _this_ section/cell
UIControl *textControl = [self.sections objectAtIndex:section];
// now we have a fresh cell and the right textControl. drop it in
[cell addSubview:textControl];
return cell;
}
hey the reason is you are doing this things when cell is nil ? but you are not writing any code when cell is not nil.
look at this example , in this example i am adding image view in tableview cell , hence you can add textviews or any other views like this
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UIImageView *imgView;
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
imgView = [[UIImageView alloc] initWithFrame:CGRectMake(100,0,100,62)];
[imgView setImage:[UIImage imageNamed:#"img.png"]];
imgView.tag = 55;
[cell.contentView addSubview:imgView];
[imgView release];
}
else
{
imgView = (id)[cell.contentView viewWithTag:55];
}
so as showin here imgView = (id)[cell.contentView viewWithTag:55]; you have to give tag to you and write code showing above in else..
Let you try to make the cell labels and textviews by using following code. It works for me.
if (tagvalue ==3) {
static NSString *CellIdentifier = #"Cell3";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease];
}
lbl7 = [[UILabel alloc] init];
[lbl7 setFont:[UIFont boldSystemFontOfSize:20]];
[cell.contentView addSubview:lbl7];
lbl7.backgroundColor = [UIColor clearColor];
lbl7.frame = CGRectMake(120, 5, 0, 40);
lbl7.tag = 70;
[lbl7 release];
lbl8 = [[UILabel alloc] init];
[lbl8 setFont:[UIFont boldSystemFontOfSize:18]];
[cell.contentView addSubview:lbl8];
lbl8.backgroundColor = [UIColor clearColor];
lbl8.textColor = [UIColor grayColor];
lbl8.frame = CGRectMake(120, 50, 0, 40);
lbl8.tag = 80;
[lbl8 release];
lbl7 = (UILabel*)[cell.contentView viewWithTag:70];
lbl8 = (UILabel*)[cell.contentView viewWithTag:80];
lbl7.text = [[rowsarray objectAtIndex:row]objectForKey:#"name"];
lbl8.text = [[rowsarray objectAtIndex:row]objectForKey:#"flavour"];
[lbl7 sizeToFit];
[lbl8 sizeToFit];
return cell;
}
if (tagvalue ==4) {
static NSString *CellIdentifier = #"Cell4";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
lbl9 = [[UILabel alloc] init];
[lbl9 setFont:[UIFont boldSystemFontOfSize:20]];
[cell.contentView addSubview:lbl9];
lbl9.backgroundColor = [UIColor clearColor];
lbl9.frame = CGRectMake(120, 5, 0, 40);
lbl9.tag = 90;
[lbl9 release];
lbl10 = [[UILabel alloc] init];
[lbl10 setFont:[UIFont boldSystemFontOfSize:18]];
[cell.contentView addSubview:lbl10];
lbl10.backgroundColor = [UIColor clearColor];
lbl10.textColor = [UIColor grayColor];
lbl10.frame = CGRectMake(120, 50, 0, 40);
lbl10.tag = 100;
[lbl10 release];
lbl9 = (UILabel*)[cell.contentView viewWithTag:90];
lbl10 = (UILabel*)[cell.contentView viewWithTag:100];
lbl9.text = [[rowsarray objectAtIndex:row]objectForKey:#"name"];
lbl10.text = [[rowsarray objectAtIndex:row]objectForKey:#"flavour"];
[lbl9 sizeToFit];
[lbl10 sizeToFit];
return cell;
}
I had same issue. Its not the problem with table class. The issue is at the place where you are calling this tableviewcontroller. First make the object of this call in .h and then allocate in .m, thats it..
When I was declaring in viewdidload like tbl *t = [self.storyboard...];, I was also facing the same problem. But when I put tbl *t; in .h problem solved.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier] autorelease];
}
timeLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 33)];
dataLabel = [[UILabel alloc]initWithFrame:CGRectMake(105, 0, 320, 33)];
timeLabel.backgroundColor = [UIColor clearColor];
dataLabel.backgroundColor = [UIColor clearColor];
dataLabel.textColor = [UIColor whiteColor];
timeLabel.textColor = [UIColor whiteColor];
[cell.contentView addSubview:timeLabel];
[cell.contentView addSubview:dataLabel];
if(indexPath.row == 0)
{
if([storedDataArray count]>0)
{
timeLabel.text = currenttime;
dataLabel.text = textView1.text;
}
return cell; //returns empty cell if there is no data in the data base
}
if(indexPath.row == 1)
{
timeLabel.text = currenttime;
dataLabel.text = textView2.text;
return cell;
}
I have a table view
- i want to display my textlabel on left side, just beside detailTextlabel.
actually when i use textLabel.text, DetailTextLabel.Text and alignments,
they displayed but not at the position i want.
so i tried to use own labels..
but they get overwritten.
since we did not (it's not possible to) change the possition & the frame size of the cell textlabel, detailTextLabel, i added 2 labels with a frame size that i want.
but when we entered text in text views and return back to table view.. the labels get overwritten..
what to do..
is there any alternate to fixed the frame size of my text label
or to avoid overwriting of our labels
Use Custom UITableViewCell instead. You can align and place labels easily using custom tabe cells.
This link will be helpful. http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/TableView_iPhone/TableViewCells/TableViewCells.html#//apple_ref/doc/uid/TP40007451-CH7-SW1
look at the customizing section in the document.
use this code it will work perfectly
if (cell== nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MenuNameCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
NSLog(#"---------new cell agin");
}
else
{
NSArray *arrayView = [cell.contentView subviews];
for (UIView *vTemp in arrayView)
{
[vTemp removeFromSuperview];
}
NSLog(#"---No New Cell hiiii");
// Setting Tag To UIButton
_checkButton = (UIButton *)[cell.contentView viewWithTag:indexPath.row];
_cancelButton = (UIButton *)[cell.contentView viewWithTag:indexPath.row];
}
add else part only
I'm having an issue programmatically adding a subview to a UITableView cell. I am attempting to add a UITextFiled to 2 cells and a UILabel to another cell in one section of my table. The table has 3 sections and most of it is manually created. One of the cells, when selected calls an action that inserts four more cells. If the same cells is selected again, the four cells will be removed. When this action occurs, the subviews get mixed up and are on the wrong cells. The keyboard also does not respond to the done key.
I try to create the subviews inside the if (cell == nil) conditional statement. Here is my code that creates the cells (sorry for it being so messy, I've been trying a ton of things):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSLog(#"cell created");
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
if (indexPath.section == 0 && indexPath.row == 0 && ([cellText objectAtIndex:indexPath.row] == #"Weight")) {
exerciseWeight = [[[UITextField alloc] initWithFrame:CGRectMake(0, 12, 295, 30)] autorelease];
exerciseWeight.textAlignment = UITextAlignmentRight;
exerciseWeight.adjustsFontSizeToFitWidth = YES;
exerciseWeight.textColor = [UIColor blackColor];
exerciseWeight.backgroundColor = [UIColor clearColor];
exerciseWeight.tag = 89899;
exerciseWeight.keyboardType = UIKeyboardTypeNumberPad;
[exerciseWeight setReturnKeyType:UIReturnKeyDone];
exerciseWeight.clearButtonMode = UITextFieldViewModeNever;
[exerciseWeight setEnabled: YES];
[exerciseWeight setDelegate:self];
[cell addSubview:exerciseWeight];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryNone;
} else if (indexPath.section == 0 && indexPath.row == 1) {
NSLog(#"Created metric subview");
metric = [[[UILabel alloc] initWithFrame:CGRectMake(100, 5, 180, 30)] autorelease];
metric.textAlignment = UITextAlignmentRight;
metric.textColor = [UIColor grayColor];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
metric.tag = 89898;
[cell addSubview:metric];
} else if (([cellText count] - 1) == indexPath.row){
exerciseReps = [[[UITextField alloc] initWithFrame:CGRectMake(0, 12, 295, 30)] autorelease];
exerciseReps.textAlignment = UITextAlignmentRight;
exerciseReps.adjustsFontSizeToFitWidth = YES;
exerciseReps.backgroundColor = [UIColor clearColor];
exerciseReps.tag = 89890;
exerciseReps.keyboardType = UIKeyboardTypeNumberPad;
[exerciseReps setReturnKeyType:UIReturnKeyDone];
exerciseReps.clearButtonMode = UITextFieldViewModeNever;
[exerciseReps setEnabled:YES];
[exerciseReps setDelegate:self];
[cell addSubview:exerciseReps];
} else if (indexPath.section == 2) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
} else {
exerciseWeight = (UITextField *)[cell viewWithTag:89899];
metric = (UILabel *)[cell viewWithTag:89898];
exerciseReps = (UITextField *)[cell viewWithTag:89890];
}
if (indexPath.section == 0) {
cell.textLabel.text = [cellText objectAtIndex:indexPath.row];
}
// Configure the cell...
if (indexPath.section == 0 && indexPath.row == 0) {
cell.textLabel.textAlignment = UITextAlignmentLeft;
exerciseWeight.placeholder = #"160";
} else if (indexPath.section == 0 && indexPath.row == 1) {
metric.text = metricUnit;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
} else if (cell.textLabel.text == #"Repetitions"){
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryNone;
exerciseReps.placeholder = #"10";
} else if (indexPath.section == 1) {
cell.textLabel.text = #"Log New Set";
cell.textLabel.textAlignment = UITextAlignmentCenter;
cell.accessoryType = UITableViewCellAccessoryNone;
} else if (indexPath.section == 2) {
cell.textLabel.text = #"History";
} else if (cell.textLabel.text == #" Pounds") {
cell.textLabel.textColor = [UIColor grayColor];
cell.textLabel.font = [UIFont systemFontOfSize:14];
} else if (cell.textLabel.text == #" Kilograms") {
cell.textLabel.textColor = [UIColor grayColor];
cell.textLabel.font = [UIFont systemFontOfSize:14];
} else if (cell.textLabel.text == #" Miles") {
cell.textLabel.textColor = [UIColor grayColor];
cell.textLabel.font = [UIFont systemFontOfSize:14];
} else if (cell.textLabel.text == #" Kilometers") {
cell.textLabel.textColor = [UIColor grayColor];
cell.textLabel.font = [UIFont systemFontOfSize:14];
}
return cell;
// [exerciseWeight release];
// [metric release];
// [exerciseReps release];
}
looks like you're going to have some fun here. But it will be satisfying once you're done :-)
I'm not sure the code you posted is the bit you need to be worrying about. Defining what you see in your table (primarily) are methods like heightForRowAtIndexPath, numberOfSectionsInTableView and numberOfRowsInSection. If you get those right you will get the display you want. So when you tap a cell you will be modifying your underlying data structures, then calling reloadData - causing the table view to call those methods all over again.
Regarding laying out those cells I don't see you using the cell's contentView at all. Have you taken a look at the Cocoa With Love blog, specifically Easy custom UITableView drawing and UITableView construction, drawing and management (revisited)? I have also used the xib method of defining table view cells as described in the Apple docs, Table View Programming Guide for iOS and given the way Xcode just keeps improving interface builder's interaction with code would probably continue to do so. I was very much against IB but now see the value in using it since Xcode 4 took away the pain of switching apps to use it, there are a lot fewer opportunities to make mistakes.
What I'm thinking is that when you "add a view" to a cell you should just switch to another cell that you have defined and load the cell, after reloadData, as required. When you want to add cells you change your underlying data structures and let the table display itself.
On the question of cell identifiers - you can either use one cell identifier and save only the cost of creating a cell, factoring out everything common that you do to all your cells, OR you can create cells with a unique identifier per type of cell and reuse cell variant TK421 when your section/row indicates a TK421 is required. I tend to do the second. I don't actually know which one performs better, but I'm sure that either is better than no reuse at all.
First question on this site, although I have been around for a while behind the scenes. I have a problem that I have been racking my head on for the last two days and I hope someone can shed some light on it for me.
I have a UITableView, which is loaded from a SQL database. It has 15 entries in it. I have inserted an extra cell at the beginning of the UITableView. This extra cell is for a UITextField and UIButton which adds an item into the database.
When the view is loaded, the first cell with the custom objects shows fine, and the rest of the table is filled with items from the database and looks just how it should. However, when the UITableView is scrolled down so the first cell is out of view, then back up, it takes the value of the 11th row item and shows it over top the first cell.
Here is my code:
- (UITableViewCell *)tableView:(UITableView *)popTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
static NSInteger NameTag = 1;
UITableViewCell *cell = [popTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
CGRect frame;
frame.origin.x =50;
frame.origin.y =10;
frame.size.height =22;
frame.size.width =275;
UILabel *nameLabel = [[UILabel alloc] initWithFrame:frame];
nameLabel.tag = NameTag;
nameLabel.opaque = YES;
nameLabel.textColor = [UIColor grayColor];
nameLabel.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:nameLabel];
[nameLabel release];
}
int row = [indexPath row];
if (row == 0) {
UIButton *buttonLeft = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonLeft setFrame: CGRectMake( 205, 6, 40, 33)];
[buttonLeft addTarget:self action:#selector(addToList:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:buttonLeft];
//No Alloc for txtField, it is built in IB
[txtField setBorderStyle:UITextBorderStyleNone];
[txtField setFrame: CGRectMake( 17, 12, 180, 23)];
txtField.backgroundColor = [UIColor clearColor];
[txtField addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
txtField.clearButtonMode = UITextFieldViewModeAlways;
}else{
UILabel * nameLabel = (UILabel *) [cell.contentView viewWithTag:NameTag];
Add *theObj = [self.theArray objectAtIndex:indexPath.row - 1];
[nameLabel setText:theObj.itemName];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
UIImageView *imageView = [cell viewWithTag:kTagCellImageView];
if (imageView == nil) {
imageView = [[UIImageView alloc]initWithFrame:CGRectMake(10.0, 10.0, 13.0, 25.0)];
imageView.backgroundColor = [UIColor clearColor];
imageView.tag = kTagCellImageView;
[cell.contentView addSubview:imageView];
}
if([theObj.itemName isEqualToString:#"First Street"]){
imageView.frame = CGRectMake(14,10,13,25);
[imageView setImage:[UIImage imageNamed:#"firststreet"]];
}
else if([theObj.itemName isEqualToString:#"Second Street"]){
imageView.frame = CGRectMake(8,12,29,20);
[imageView setImage:[UIImage imageNamed:#"second"]];
}
else if([theObj.itemName isEqualToString:#"Main Street"]){
imageView.frame = CGRectMake(15,10,13,25);
[imageView setImage:[UIImage imageNamed:#"mainstreet"]];
}
else{
imageView.frame = CGRectMake(8,8,25,25);
[imageView setImage:[UIImage imageNamed:#"iconcustom"]];
}
NSLog(#"%#",itemName);
NSLog(#"%#",itemCategory);
}
return cell;
}
Also here is my cellForRow:
- (NSInteger)tableView:(UITableView *)popTableView numberOfRowsInSection:(NSInteger)section {
return [self.theArray count] + 1; //Add Extra cell to beginning
}
Any ideas would be greatly appreciated.
You need to use a different reuseIdentifier for your first cell. Try this:
NSString *cellIdentifier;
if (indexPath.row == 0) {
cellIdentifier = #"first";
} else {
cellIdentifier = #"not first";
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
// .. cell initialization
}
Obligatory tangential answer - have you thought about setting the tableHeaderView on the UITableView instead? I think that'd accomplish what you're trying to do in a cleaner way (in that it adds an arbitrary view to the top of the table).
Just create a UIView with your "add a new item" controls in it and then set it as the header view when first creating the table.
The issue is here
static NSString *CellIdentifier = #"Cell";
static NSInteger NameTag = 1;
UITableViewCell *cell = [popTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
you are dequeueing all of the cells with the same identifier. Row 1 (index 0) needs to have its own CellIdentifier. Also it looks like you keep adding subviews to the same cells that you dequeue. On your if(cell == nil) check you may want to decide if you want to remove all of the cells contentView subviews or reuse them.