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;
}
Related
What I want
There is a tableview.I just want to hide a UIButtonTypeContactAdd accessory by tapping it in the TableViewCell.
My problem
When I tapped the accessory button A(which I only tapped in the whole procedure) , it hided correctly. But when I scrolled down the tableview , I found another accessory button B was hided ridiculously. After scrolling quickly to the top side of the tableview , the button B guy was there again , meanwhile another button C hided...
It's pity I can't put images in my post.Hope you can understand what happened.
Code
tableView:cellForRowAtIndexPath:
static NSString *CellIdentifier = #"All Name Showing Table";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if(!cell.accessoryView){
UIButton *button = [UIButton buttonWithType:UIButtonTypeContactAdd];
[button addTarget:self action:#selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
cell.accessoryView = button;
}
- (IBAction)buttonTapped:(UIButton *)sender
{
UITableViewCell *tvc = (UITableViewCell *)[sender superview];
NSString *peopleTapped = [NSString stringWithFormat:#"you have favored %#",tvc.textLabel.text];
NSLog(#"%#",peopleTapped);
sender.hidden = YES;
}
Is all of this because of the mechanism of cell reuse?
Sorry for my poor English.
Thanks!
You can't use table this way. You should have a data model with object which store button accessory button state.
static NSString *CellIdentifier = #"All Name Showing Table";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if(!cell.accessoryView){
UIButton *button = [UIButton buttonWithType:UIButtonTypeContactAdd];
[button addTarget:self action:#selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
cell.accessoryView = button;
}
Model *model = [_array objectAtIndex:indexPath.row];
button.tag = [_array indexOfObject:indexPath.row];
button.hidden = model.hidden;
....
}
- (IBAction)buttonTapped:(UIButton *)sender
{
Model *model = [_array objectAtIndex:sender.tag];
model.hidden = YES;
[table reloadData];
}
Something like this.
Yes, it's happening because of cell reuse. You need to be able to keep track of each button in the tableview, probably by aligning it with your data source. This could be easily accomplished by having your cell data source keep track of the state of each button.
my app has a bug, and i believe its because I'm not reseting the cells content. The apple docs say
The table view’s data source implementation of tableView:cellForRowAtIndexPath: should always reset all content when reusing a cell.
Could someone please explain how to do this, or point me to a tutorial? Thank you in advance!
My cellForRow
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *identifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
addBtn = [[UIButton alloc]init];
addBtn =[UIButton buttonWithType:UIButtonTypeRoundedRect];
[addBtn setFrame:CGRectMake(220,10,25,55)];
[addBtn addTarget:self action:#selector(addLabelText:) forControlEvents:UIControlEventTouchUpInside];
[addBtn setTitle:#"+" forState:UIControlStateNormal];
[addBtn setEnabled:YES];
[cell addSubview:addBtn];
subBtn = [[UIButton alloc]init];
subBtn=[UIButton buttonWithType:UIButtonTypeRoundedRect];
[subBtn setFrame:CGRectMake(260,10,25,55)];
[subBtn addTarget:self action:#selector(subtractLabelText:) forControlEvents:UIControlEventTouchUpInside];
[subBtn setTitle:#"-" forState:UIControlStateNormal];
[subBtn setEnabled:YES];
[cell addSubview:subBtn];
}
//cellText.hidden=!self.editing;
cell.textLabel.textColor = [UIColor orangeColor];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
cell.imageView.image = [imageArray objectAtIndex:indexPath.row];
cell.textLabel.text = [number objectAtIndex:indexPath.row];// <------ Is this line in the right place?
cell.textLabel.text = #"1"; // <---- Is this line in the right place?
return cell;
}
It's pretty simple. You provide the call cellForRowAtIndexPath in your code. In it, you either provide a brand new cell, or you reuse a cell that the OS has chucked into memory. Basically, you code looks like this:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
[[cell textLabel] setText:[pickerData objectAtIndex:indexPath.row]];
cell.accessoryType = (indexPath.row == currentValueOfIndex ) ?
UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
return cell;
The part under the comment // Configure the cell is where you have to reset your cells content. Since it can either be a new cell, or a recycled cell, it will either have no information, or the information from another cell where it was recycled from. In both cases, you provide the cell's text and accessories and anything else you want to use each time the cell is called. Basically, it's a callback to you to provide a cell, either a brand new one, or a recycled one, and you have to stuff the right info for the cell it's going to be (based on the index path). Hope I made this clear enough.
If you're adding views programmatically to the cell, you should do the following for cleaning them:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
for (UIView * v in cell.contentView.subviews) {
[v removeFromSuperview]
}
//Configure your cell
return cell;
}
See the comments in the code below...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// this is where you want to configure your generic cell
// for example, if EVERY cell needs to have a disclosure indicator, you could do
cell.accessoryType = UITableViewAccessoryTypeDisclosurseIndicator;
}
// this is where you want to put code that would or could be unique to a cell
// for example, if you wanted to put the row number you could do:
cell.textLabel.text = [NSString stringWithFormat:#"%d", indexPath.row];
// you would put this here and not in the above if statement because the value of the textLabel changes for different cells
return cell;
}
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 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.
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...