I have had couple of encounters of this and what I am trying to do is basically calling tableView reloadData however not all the values in the cell is getting updated.The top 5 rows is always not updated... I'd have to scroll to the bottom and then up again to get it updated. Why is this happening?
Here's my code:
- (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];
[cell.textLabel setFont:[UIFont fontWithName:#"Arial" size:16]];
}
//add a button to set to accessory view
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
//I missed setting the frame yesterday!
//[button setFrame:CGRectMake(200, 20, 20, 20)];
[button setImage:[UIImage imageNamed:#"addsource.png"] forState:UIControlStateNormal];
[button addTarget:self action:#selector(changeButton:) forControlEvents:UIControlEventTouchUpInside];
[button setBackgroundColor:[UIColor clearColor]];
cell.accessoryView = button;
if ([[self.content objectAtIndex:indexPath.row] isKindOfClass:[Source class]]){
Source * source = [self.content objectAtIndex:indexPath.row];
if (![source.type isEqualToString:#"featured"]){
[cell.textLabel setText:source.domain];
NSURL* URL = [NSURL URLWithString:source.imageUrl];
[cell.imageView setImageWithURL:URL
placeholderImage:[UIImage imageNamed:#"placeholder.jpg"]];
}
}
return cell;
}
and this is called everytime I refresh the whole data set:
[self.content removeAllObjects];
[self.content addObjectsFromArray:objects];
[self.tableView reloadData];
try debugging the following line:
if (![source.type isEqualToString:#"featured"]){
obviously your cell won't get updated in the case where your source type is "featured". double check all values in your content array
I've not dug into your code, but this sounds like a symptom you might see when cells are being reused without being fully reset from their previous appearance.
When a cell gets dequeued, it doesn't get reset, it just gets removed from the table view. So unless you do reset it when it next happens to be allocated, it carry previous config and settings.
So, when you configure a cell, make sure you restore all aspects of the cell in all cases, not just those settings for a particular variant of the cell you happen to be returning this time.
Hope that helps.
Related
I have a UITableView with method cellForRowAtIndexPath shown below, the problem is that cellImage only appears after having scrolled completely up (so no rows are visible) and then releasing. The strange thing is that I have identical code in another class for a separate table view and the image appears fine. Any ideas?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryNone;
}
[cell.textLabel setText:[items objectAtIndex:indexPath.row]];
[cell.textLabel setFont:[UIFont fontWithName:#"Helvetica" size:15.0f]];
[cell.textLabel setTextColor:[UIColor whiteColor]];
[cell setBackgroundColor:[[UIColor alloc] initWithRed:117.0/255.0 green:118.0/255.0 blue:121.0/255.0 alpha:1.0]];
[self.tableView setBackgroundView:nil];
[self.tableView setBackgroundView:[[UIView alloc] init]];
[self.view setBackgroundColor:[[UIColor alloc] initWithRed:167.0/255.0 green:169.0/255.0 blue:172.0/255.0 alpha:1.0]];
UIImageView *cellImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"next#2x.png"]];
[cell addSubview:cellImage];
[cellImage setFrame:CGRectMake(0, 0, 26, 24)];
[cellImage setCenter:CGPointMake(cell.frame.size.width - 30, cell.frame.size.height/2)];
return cell;
}
[self.tableView setBackgroundView:nil];
[self.tableView setBackgroundView:[[UIView alloc] init]];
The lines dont belong to the method. You call the methods every time you scroll for every cell. Put them in your viewDidLoad method, after you have created your table view.
UIImageView *cellImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"next#2x.png"]];
[cell addSubview:cellImage];
These lines are really very BAD and may cause a memory leak.
Everytime you scroll the table view you add a imageview to the cell. Table view reuses the cells. It means when cell is reused, you add a new imageview to the cell. After you scroll more times you have x times imageview on every cell, unless you remove them somewhere in you code.
Other point is, if you want to add some subview to a cell (eg. in init method of the cell) then add it to contenview of the cell like this
[cell.contentView addSubview:someView];
Otherwise your subview may overlap accessory views. And you can have problems when your cell is resized.
I advise you read the guide from the following link:
http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/tableview_iphone/TableViewCells/TableViewCells.html#//apple_ref/doc/uid/TP40007451-CH7-SW1
As captured in many of the comments, there are a number of issues:
Set your view and tableView background in your viewDidLoad method (or via your XIB), not in cellForRowAtIndexPath
Use the cell.imageView property to set a left icon, OR, alternatively, to build a custom cell you would use [cell.contentView addSubview:cellImage]. If you do the latter, you should also add your textLabel in the same manner as a UILabel.
To set the background of a tableview cell, use this delegate method:
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell*)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
[cell setBackgroundColor:[[UIColor alloc] initWithRed:117.0/255.0 green:118.0/255.0 blue:121.0/255.0 alpha:1.0]];
}
though for efficiency you should instantiate this UIColor once in your viewcontroller and set it as [cell setBackgroundColor:self.cellBackground];
The problem you are facing is due to reuseIdentifier for cell.
Also you are creating Imageview everytime cellForRowAtIndexPath is executed.
i will suggest two solution here for you.
1st Option :- just replace this code :
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.accessoryType = UITableViewCellAccessoryNone;
}
this is not proper way when you are dealing with dynamic images, means you are downloading thumbnail from server and data content is more, if it's small and static data then it's fine for you.
2nd Option :- just use this formatted code this will not create imageview everytime just use object from current cell with tag.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryNone;
UIImageView *cellImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 26, 24)];
cellImage.tag = 88;
[cell addSubview:cellImage];
[cellImage setCenter:CGPointMake(cell.frame.size.width - 30, cell.frame.size.height/2)];
}
[cell.textLabel setText:[items objectAtIndex:indexPath.row]];
[cell.textLabel setFont:[UIFont fontWithName:#"Helvetica" size:15.0f]];
[cell.textLabel setTextColor:[UIColor whiteColor]];
[cell setBackgroundColor:[[UIColor alloc] initWithRed:117.0/255.0 green:118.0/255.0 blue:121.0/255.0 alpha:1.0]];
[self.tableView setBackgroundView:nil];
[self.tableView setBackgroundView:[[UIView alloc] init]];
[self.view setBackgroundColor:[[UIColor alloc] initWithRed:167.0/255.0 green:169.0/255.0 blue:172.0/255.0 alpha:1.0]];
UIImageView *cellImage = (UIImageView *)[cell viewWithtag:88];
cellImage.image = [UIImage imageNamed:#"next#2x.png"];
}
Fixed using the following code:
UIImageView *cellImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"next#2x.png"]];
[cell setAccessoryView:cellImage];
i wants just know.... to add buttons in each cell in table row.....programmatically in runtime
and also wants identify the button when clicked....
i write little code..here....
//---insert individual row into the table view---
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[NSString stringWithFormat:#"Cell %i",indexPath.section]];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:[NSString stringWithFormat:#"Cell %i",indexPath.section]] autorelease];
}
NSLog(#"i am here in table function..........now");
//cell.textLabel.text = [data objectAtIndex: indexPath.row];
search_items *pro = [searchCount objectAtIndex:[indexPath row]];
cell.textLabel.text = pro.s_showroomName;
UIButton* aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setTag:[indexPath row]];
[aButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:aButton];
return cell;
}
-(void)buttonClicked:(UIButton*)sender {
int tag = sender.tag;
///and rest code here.....
}
this code not work properly....:)
please give me solution :)
thanks in advance.....please give me any tutorial also..
set the frame for your button like this..
aButton.frame = CGRectMake(0, 0,150,44);
chck the question you may get some help runtime adding button and calling methods on them. iPhone: Add UIButton's horizontally with scrollbar provision in a View or TableView?
I have a tableview in which I am trying to place a button with an image and a label. I want to change the image of the button once clicked.
Here's the code:
- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
checkedImg = [UIImage imageNamed:#"buttonUnChecked1.png"];
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
//Set up the cell...
NSString *cellValue = [suggestions objectAtIndex:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
check = [UIButton buttonWithType:UIButtonTypeCustom];
check.frame=CGRectMake(0,35,20,20);
[check setImage:checkedImg forState:UIControlStateNormal];
[check addTarget:self action:#selector(checkClicked:) forControlEvents: UIControlEventTouchUpInside];
[cell.contentView addSubview:check];
cellContent = [[UILabel alloc]initWithFrame:CGRectMake(40,32,500,25)];
cellContent.text = cellValue;
[cell.contentView addSubview:cellContent];
return cell;
}
-(void)checkClicked:(UIButton *)b
{
checkedImg = [UIImage imageNamed:#"buttonChecked1.png"];
[check setImage:checkedImg forState:UIControlStateNormal];
}
By doing this, the image of the buttons are getting changed but only the last one and not the one clicked. I know the reason behind it, but I don't know how to achieve what I want.
A structured way to get the result you're looking for:
Make a UIView subclass that for your table cells (containing a button and label). You instantiate these custom views and set them as your contentView for each table cell in cellForRowAtIndexPath.
Each of your custom views listens for its own button being pressed. When it was pressed, it toggles its state and tells the main viewcontroller (via a delegate method) that it was toggled. The main view controller calls reloadData on the cell in question to cause it to be reloaded with the correct appearance.
Note that this approach requires you to tell each of the custom views which index path it is rendering for in the table -- that way it can inform the main view controller's delegate method -- this info is needed for triggering a reload of the appropriate cell.
Btw, I presume you want to look at the state of the buttons in your table when the user is done with editing, and your current approach doesn't capture the state stuff very explicitly -- you'd have to iterate over your buttons, or add selected items to a mutable array, or something.
The easy answer to your problem is to change your checkClicked: method to this:
-(void)checkClicked:(UIButton *)b
{
[b setImage:[UIImage imageNamed:#"buttonChecked1.png"] forState:UIControlStateNormal];
}
But you should also adjust your tableView:cellForRowAtIndexPath: method to avoid creating the button repeatedly and to clean up some memory issues like this:
- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UIButton *checkBtn = [UIButton buttonWithType:UIButtonTypeCustom];
checkBtn.frame = CGRectMake(0,35,20,20);
[checkBtn setImage:[UIImage imageNamed:#"buttonUnChecked1.png"]; forState:UIControlStateNormal];
[checkBtn addTarget:self action:#selector(checkClicked:) forControlEvents: UIControlEventTouchUpInside];
[cell.contentView addSubview:checkBtn];
UILabel *cellContentLbl = [[UILabel alloc]initWithFrame:CGRectMake(40,32,500,25)];
cellContentLbl.tag = 1;
[cell.contentView addSubview:cellContentLbl];
[cellContentLbl release];
}
//Set up the cell...
NSString *cellValue = [suggestions objectAtIndex:indexPath.row];
cellContent = (UILabel *)[cell viewWithTag:1];
cellContent.text = cellValue;
return cell;
}
Please look at my following code snippet. I place check box in to my cell , i can able to check or uncheck the checkbox. but when i scroll the table view the checkbox's check mark is getting hidden.
i mean i set the check mark by setting the image.
Please anybody help me to solve this problem.
Thanks for your time.
// 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:UITableViewCellStyleDefault reuseIdentifier:#"en"] autorelease];
cb = [[UIButton alloc] initWithFrame:CGRectMake(5,10, unselectedImage.size.width, unselectedImage.size.height)];
[cb setImage:unselectedImage forState:UIControlStateNormal];
[cb setImage:selectedImage forState:UIControlStateSelected];
[cb addTarget:self action:#selector(buttonAction:) forControlEvents:UIControlEventTouchDown];
[cell.contentView addSubview:cb];
}
if ( tableView == myTableView )
{
titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(60, 0, 150, 35)];
titleLabel.font = [UIFont boldSystemFontOfSize:13];
titleLabel.textColor = [UIColor blackColor];
[cell.contentView addSubview:titleLabel];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
return cell;
}
Taken from here
If I understand the TableView concept correctly, you need to save the checkmark setting somewhere else. If your cell gets scrolled out of view the TableViewController might release the cell. Then, when you're asked to re-create the cell in your delegate, you have to restore it in the same state as before.
In DidSelectRowAtindexPath:
if ([set containsObject:indexPath])
{
[set removeObject:indexPath];
}
else
{
[set addObject:indexPath];
}
and in CellForRpwAtIndexPath:
if ([set containsObject:indexPath])
{
cell.imgView.image=[UIImage imageNamed:#"chealBox1.png"];
}
else
{
cell.imgView.image=[UIImage imageNamed:#"chealBox2.png"];
}
here set is NSMutableSet and you have to make property and synthesize and alloc as well in viewDidLoad...will work definitely...
I am trying to have a button for selected rows of my table.
Here is the example code I am using:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ControlRowIdentifier = #"ControlRowIdentifier";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:ControlRowIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:ControlRowIdentifier] autorelease];
}
if ([indexPath row] > 5) {
UIImage *buttonUpImage = [UIImage imageNamed:#"button_up.png"];
UIImage *buttonDownImage = [UIImage imageNamed:#"button_down.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0.0, 0.0, buttonUpImage.size.width, buttonUpImage.size.height);
[button setBackgroundImage:buttonUpImage forState:UIControlStateNormal];
[button setBackgroundImage:buttonDownImage forState:UIControlStateHighlighted];
[button setTitle:#"Tap" forState:UIControlStateNormal];
[button addTarget:self action:#selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
cell.accessoryView = button;
}
NSUInteger row = [indexPath row];
NSString *rowTitle = [list objectAtIndex:row];
cell.textLabel.text = rowTitle;
return cell;
}
This code works absolutely fine when loaded for 1st time. So, as per the logic it shows 'Tap' button for all rows greater than 5.
Problem occurs when I scroll up and down. Once I do that it just starts putting that button at any random row. I dont understand why it does that and it'll be really helpful if someone can give some tips on this.
Thanks.
The problem is reusing cell's identifier. In your case, the cell with an index of less than 6 must be with one identifier, and the rest from other.
Table view cells is reusable objects and you must do some clean work with it. Try use next:
if ([indexPath row] > 5) {
...
} else {
cell.accessoryView = nil;
}