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;
}
Related
I am creating a custom button in my uitable and giving the button a tag number as shown in code below.
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//NSLog(#"Inside cellForRowAtIndexPath");
static NSString *CellIdentifier = #"Cell";
// Try to retrieve from the table view a now-unused cell with the given identifier.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// If no cell is available, create a new one using the given identifier.
if (cell == nil)
{
// Use the default cell style.
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:#selector(selectPicOnBtnTouch:)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"btn1" forState:UIControlStateNormal];
button.frame = CGRectMake(6.0f, 0.0f, 97.0f, 110.0f);
button.tag = (indexPath.row)+100;
[cell addSubview:button];
[button setImage:[UIImage imageNamed:#"sample_pic.png"] forState:UIControlStateNormal];
}
else
{
//NSLog(#"went here 2");
button = (UIButton *) [cell viewWithTag:((indexPath.row)+100)];
}
//Get an arrow next to the name
cell.accessoryType = UITableViewCellAccessoryNone;
return cell;
}
- (IBAction) selectPicOnBtnTouch:(id)sender
{
button = (UIButton *)sender;
NSLog(#"[button tag]: %d ...", [button tag]);
}
If I have a table with 10 rows and when I touch buttons in rows 1-5 I get the following in my log
[button tag]: 100 ...
[button tag]: 101 ...
[button tag]: 102 ...
[button tag]: 103 ...
[button tag]: 104 ...
This is fine. The problem is that when I touch row 6-10 I am expecting 105 - 109 tags but what I get back is same tag numbers starting over
[button tag]: 100 ...
[button tag]: 101 ...
[button tag]: 102 ...
[button tag]: 103 ...
[button tag]: 104 ...
The reason I want to keep the tag numbers unique (and not repeating) is so that I know which button corresponds to what row. How can I do that?
Before You follow my Answer i wnat to tell you that following code is bad for memory management because it will create new cell for each rows of UITableView, so be careful for it.
But it is better to use, When UITableView Have Limited rows (about 50-100 may be ) then following code is helpful in your case, use it if is it suitable for you.
- (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] autorelease];
/// Put your code here
}
return cell;
}
Don't set the button tag inside the if block where you create the cell, because cells will be reused and you are not updating the tag in the scenario when the cell is reused.
EDIT :
For the first 5 cells, if block is being executed and new cells are
being created. 6th cell onwards the cells are being reused and hence
count is not incremened.
Call your
button.tag = (indexPath.row)+100;
below your if (cell == nil) block, like this:
if (cell == nil)
{
//...
}
else
{
///...
button = (UIButton*)[[cell subviews] lastObject]; //this assumes your button is the last view in the subview array (double check)
}
button.tag = (indexPath.row)+100;
You need to do smth like that:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
self.rNewsCell = [self.tabelView dequeueReusableCellWithIdentifier:allNewsCellIdentifier forIndexPath:indexPath];
if (self.news.count != 0)
{
if(indexPath.row <[self.news count])
{
RNewsModel *news = (self.news)[indexPath.row];
self.rNewsCell.newsImage.contentMode = UIViewContentModeScaleAspectFill;
self.rNewsCell.newsName.text = news.newsNameModel;
self.rNewsCell.newsData.text = news.newsDataModel;
self.rNewsCell.newsWatches.text = news.newsWatchesModel;
self.rNewsCell.newsAddress.text = news.newsAddressModel;
self.rNewsCell.newsTime.text = news.newsTimeModel;
self.rNewsCell.playFrame.image = [UIImage imageNamed: news.newsPlayImage];
self.rNewsCell.playButton.tag = indexPath.row;
self.rNewsCell.showOnMap.tag = indexPath.row;
self.rNewsCell.rightUtilityButtons = [self rightButtons];
self.rNewsCell.delegate = self;
}
}
return self.rNewsCell;
}
and after that catch the button actions:
- (IBAction)showNewsOnTheMap:(id)sender
{
UIButton *button=(UIButton *) sender;
self.showNewsOnMap = [NSIndexPath indexPathForRow:button.tag inSection:0];
RNewsModel *news = (self.news)[self.showNewsOnMap.row];
NSLog(#"didSelect NEWSOnMap = %#",news.newsIDModel);
[self performSegueWithIdentifier:SegueShowNewsOnTheMap sender:self];
}
My code is working fine but it works only for a single cell. When i define 5 rows then it works only for the last cell. If I click on 1 cell then value displayimage on last cell only it not display where i am click and which cell i am click how to handle toogle button change image for each and every cell click on button image this code.
-(void)changeMapType:(id)sender
{
//changeimagetype =!changeimagetype;
// sender.selected = changeimagetype;
//sender.selected
changeimagetype =!changeimagetype;
if(changeimagetype == YES)
{
//flagButton=1;
//[check setImage:[UIImage imageNamed:#"alarm_OF.png"] forState:UIControlStateNormal];
onButtonView.image = [UIImage imageNamed:#"alarm_OF.png"];
[mimageButton setImage:onButtonView.image forState:UIControlStateNormal];
}
else
{
//flagButton=2;
onButtonView.image = [UIImage imageNamed:#"alarm_ON.png"];
[mimageButton setImage:onButtonView.image forState:UIControlStateNormal];
}
[self.tableView reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 2;
}
// 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:CellIdentifier] autorelease];
mimageButton = [UIButton buttonWithType:UIButtonTypeCustom];
mimageButton.frame=CGRectMake(10, 10, 20, 20);
mimageButton.tag = 1;
//mimageButton = [UIButton buttonWithType:UIButtonTypeCustom];
//[mimageButton setImage:[UIImage imageNamed:#"alarm_ON.png”] //forState:UIControlStateNormal];
//[mimageButton setImage:[UIImage imageNamed:#"alarm_OF.png”] //forState:UIControlStateSelected];
onButtonView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
onButtonView.tag = 2;
onButtonView.image = [UIImage imageNamed:#"alarm_ON.png”];
[mimageButton setBackgroundImage:[onButtonView.image stretchableImageWithLeftCapWidth:0.0 topCapHeight:0.0] forState:UIControlStateNormal];
[cell.contentView addSubview:mimageButton];
[mimageButton addTarget:self action:#selector(changeMapType:) forControlEvents: UIControlEventTouchUpInside];
}
Can you help me correcting the code?
Try giving the tag for the button as the row number of the table. Then check the tag in the button press method and then perform the logic to change image.
-(void)changeMapType:(id)sender
{
UIButton *button = (UIButton *)sender;
// Check tag of button
// Some code
//Change image after checking
[button setImage:yourImage forState:UIControlStateNormal];
}
Take an Array, Store the selected buttons tag in the array and while displaying the button in the cellForRowAtIndex method. check out whether the buttons tag is in that array or not. If its there then show your selected button image else unselected buttons image.
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've got a UITableView containing three sections.
Section 1 has one cell containing a UISwitch failAtLaunch in its accesoryview
Section 2 contains the items from the failSounds array and has a singular checkmark for the selected item (sound in this case)
Section 3 contains a button.
You can see below how I configure the cells..
The problem is that the table gives strange behaviour. Whenever I scroll up and down the tableview, with cells moving in and out of view, some cells in section 2 get the UISwitch failAtLaunchin their accesoryview.
Can anyone help me understand why this is?
Thanks in advance!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//....blablabla...
// Configure the cell...
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *theSound = [prefs objectForKey:#"pickedFailSound"];
NSUInteger index = [failSounds indexOfObject:theSound];
if (indexPath.section == 0){
failAtLaunch = [[[UISwitch alloc] initWithFrame:CGRectMake(200, 7, 100, 30)] autorelease];
[cell addSubview:failAtLaunch];
cell.accessoryView = failAtLaunch;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
if(![prefs boolForKey:#"failAtLaunch"]) {
[failAtLaunch setOn:NO animated:NO];
} else {
[failAtLaunch setOn:YES animated:NO];
}
[(UISwitch *)cell.accessoryView addTarget:self action:#selector(setIt) forControlEvents:UIControlEventValueChanged];
cell.textLabel.text = #"Instafail";
return cell;
} else if (indexPath.section == 1) {
NSString *cellTitle = [failSounds objectAtIndex:indexPath.row];
cell.textLabel.text = cellTitle;
if (indexPath.row == index) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
return cell;
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"buttonCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"buttonCell"] autorelease];
}
cell.textLabel.text = #"Hold to record fail sound";
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.frame = CGRectMake(230.0f, 4.0f, 60.0f, 36.0f);
[btn setTitle:#"OK" forState:UIControlStateNormal];
[btn setTitle:#"OK" forState:UIControlStateSelected];
[btn addTarget:self action:#selector(recordAudio) forControlEvents:UIControlEventTouchDown];
[btn addTarget:self action:#selector(stop) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:btn];
return cell;
}
}
The problem is from the dequeueReusableCellWithIdentifier: use different static strings for each type of cell.
It's your blah blah blah section. I think you are probably using the same reuse-identifier for all 3 types of rows, and not clearing them out prior to re-use.
So when you instantiate a new tableViewCell, you need to switch on section and give each one a unique identifier.
What I usually do is tag every view that I add to a cell with a tag like "CLEAR_ME_OUT" that is defined as some large arbitrary number. Then when I re-use a cell, I loop through the sub-views and removeFromSuperview all cells with that tag. That way it's nice a clean for re-use.
I have a table containing images and buttons. Each button has a tag with a different number. All buttons execute the same method when clicked. I will use the button's tag on the method they run, to know which button was clicked.
The problem is that the button's tag being reported is wrong. I imagine that as the cells are being reused, something is interfering with the tag.
This is the code I am using to populate the table on the fly:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
UIButton *buyButton = [[UIButton alloc] initWithFrame:CGRectMake( 220, 4, 100, 35)];
buyButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
buyButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
[buyButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
buyButton.titleLabel.font = [UIFont boldSystemFontOfSize:14];
[buyButton setBackgroundImage:newImage forState:UIControlStateNormal];
[buyButton addTarget:self action:#selector(buyNow:) forControlEvents:UIControlEventTouchDown];
[buyButton setTag: 1]; // I have to do this, to locate the button a few lines below
[cell addSubview:buyButton];
[buyButton release];
}
imageU = [[[UIImage alloc]initWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:[NSString stringWithFormat: #"table-pg%d",numberX]
ofType:#"jpg"]] autorelease];
cell.imageView.image = imageU;
UIButton * myButton = (UIButton *) [cell viewWithTag:1];
[myButton setTitle:NSLocalizedString(#"buyKey", #"") forState:UIControlStateNormal];
UIImage *newImage = [[[[UIImage alloc]initWithContentsOfFile:[[NSBundle mainBundle]
pathForResource: #"whiteButton" ofType:#"png"]] autorelease]
stretchableImageWithLeftCapWidth:12.0f topCapHeight:0.0f];
[buyButton setTag:indexPath.row]; // the button's tag is set here
return cell;
}
and this is the buyNow method...
- (void) buyNow:(id)sender {
int index = [sender tag];
NSLog(#"button clicked = %d", index);
}
the button being reported as the clicked one cycles from 0 to 6, no number beyond 6 is ever reported. I think this corresponds to the cells being reused, why the number is not changing, is a mystery.
How to solve that?
thanks for any help.
Try moving the code that creates and sets up the button and adds it to the cell to the willDisplayCell method:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
I think this will allow you to reuse cells and also have a unique instance of the button in each one.