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];
}
Related
I have a table view and in each row there is a add button on click the new row adding below i want that onclick the row has one text field in it and a user can enter a texh on it can you help me how to add a text field in the adding row.
here is my code
-(void)buttonclicked:(UIButton *)sender
{
UIButton *btn = (UIButton *)[self.view viewWithTag:sender.tag];
NSLog(#"clickedCell=%i", btn.tag);
[[NSUserDefaults standardUserDefaults]setValue:[NSString stringWithFormat:#"%i", btn.tag] forKey:#"btntag"];
[self.choices insertObject:#"newrow" atIndex:btn.tag+1];
[self.tableView reloadData];
}
and the table view method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UIButton *button = [UIButton buttonWithType:UIButtonTypeContactAdd];
button.tag = indexPath.row;
button.frame = CGRectMake(280.0, 10, 25, 30.0); // x,y,width,height
[button addTarget:self action:#selector(buttonclicked:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:button];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:cell action:nil];
longPress.delegate = self;
[cell addGestureRecognizer:longPress];
int count = 0;
if(self.editing && indexPath.row != 0)
count = 1;
NSLog([NSString stringWithFormat:#"%i,%i",indexPath.row,(indexPath.row-count)]);
// Set up the cell...
if(indexPath.row == ([_choices count]) && self.editing)
{
cell.textLabel.text = #"ADD";
return cell;
}
NSString *choice = [self.choices objectAtIndex:indexPath.row];
cell.textLabel.text = choice;
return cell;
}
try like this may be it helps to you,
1.take one global variable type integer for example position.
2.when you click on particular button -(void)buttonclicked:(UIButton *)sender method will call in this method you will assign the btn.tag value to the position .
3.after that you are reloading the table view in the tableview cellForRowAtIndexPath method take one condition like
if(position==indexpath.row)
{
//add your textfield here
}.
I am new to iphone.I have a small doubt (i.e),I have create a table view in that i am placing all my book names and download option to that particular book in each cell like as below
Genesis Download
Exodus Download
Leviticus Download
Here is the above Genesis,Exodus,Leviticus are booknames and download is the button for download that book like this i have 66 different books in table view.Here my question is when we click on download button i want to get the corresponding bookname of that tableview cell.
My code is like below
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 66;
}
- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UIButton *downloadButton = nil;
//this is the custom cell i have created one class for this in that i am place the string titlelabel.
CustomCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
downloadButton = [UIButton buttonWithType:UIButtonTypeCustom];
downloadButton.frame = CGRectMake(220,10,50,30);
[downloadButton setImage:[UIImage imageNamed:#"download.png"] forState:UIControlStateNormal];
[downloadButton addTarget:self action:#selector(downloadButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
downloadButton.backgroundColor = [UIColor clearColor];
downloadButton.userInteractionEnabled = YES;
downloadButton.highlighted = YES;
[cell.contentView addSubview:downloadButton];
}
NSString *titleLabel = [[appDelegate getBookNames]objectAtIndex:indexPath.row];
cell.TitleLabel.text = titleLabel;
return cell;
}
-(void)downloadButtonClicked:(id)sender{
}
In the button action you can get the cell by accessing the superView
-(void)downloadButtonClicked:(id)sender{
UIButton *button = (UIButton*)sender;
UIView *view = button.superview; //Cell contentView
UITableViewCell *cell = (UITableViewCell *)view.superview;
cell.textLabel.text; //Cell Text
}
first set the tag of your label say it is 100.
//in the button click method...
UITableViewCell *cell = (UITableViewCell *)[[button superview] superview];
UILabel *lbl = (UILabel *)[cell viewWithTag:100];//this is for custom label
NSLog(#"label text =%#",lbl.text);
else NSLog(#"label text =%#",cell.titleLabel.text);
When you tap on the table view cell the Delegate function will be called and it will give you the index path section and row value . When you putting button on table cells just allocate the tag - indexpath.row to the button tag. Find this tag when you call the button function and find the aray index to get the value for that index on the array.
I have a tableViewController, the cells contains a button and a label. I need to get the text of the cell (actually the object of the cell Person) when the user clicks on the button.
When the user clicks on the button the following method gets executed;
-(void) buttonOfCellClicked{
// here i need to access the `Person` object that the user clicked
}
How do i write this code?
EDIT:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Person *person = [personsArr objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] ;
label = [[UILabel alloc]initWithFrame:CGRectMake(15, 5, 75, 60)];
label.text =person.firstName;
[cell addSubview:label];
UIButton *button= [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self action:#selector(buttonOfCellClicked) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:button];
}
id findAncestor(UIView *view, Class class) {
while (view && ![view isKindOfClass:class])
view = [view superview];
return view;
}
- (void)buttonOfCellClicked:(UIButton *)button
{
UITableViewCell *cell = (UITableViewCell *)findAncestor(button, [UITableViewCell class]);
UITableView *table = (UITableView *)findAncestor(cell, [UITableView class]);
NSIndexPath *path = [table indexPathForCell:cell];
if (!path)
return;
Person *person = [personsArr objectAtIndex:path.row];
// do whatever with person
}
I would subclass UITableviewCell and add a property and the action to that class and in IB connect the button. When you are configuring the cell just set the person object. This approach would depend heavily on what you plan on doing with that object.
You need to ask your button to tell you where it is. To achieve this, you need to call superview twice (1x will return cell.contentView, 2x will return cell):
- (void)buttonOfCellClicked:(UIButton *)sender {
UITabvleViewCell *cell = (UITableViewCell *)[[sender superview] superview];
}
Then you can access cell's properties e.g. cell.textLabel.text
EDIT: You also need to add : to your -addTarget:action:forControlEvents: in cellForRow after buttonOfCellClicked text:
[button addTarget:self action:#selector(buttonOfCellClicked:) forControlEvents:UIControlEventTouchUpInside]
EDIT2: you can access person by
NSIndexPath *ip = [yourTableView indexPathForCell:cell];
Person *p = [personArr objectAtIndex:ip.row];
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [yourArray count];\
}
- (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] ;
UIButton *button= [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTag:indexPath.row]; // SET TAG TO YOUR BUTTON, IT WILL BE SAME AS YOUR OBJECT AT INDEX OF ARRAY
[button addTarget:self action:#selector(buttonOfCellClicked:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:button];
}
-(void) buttonOfCellClicked:(id) sender{
Person *person = [yourArray objectAtIndex:[sender tag]];
// here i need to access the `Person` object that the user clicked
}
i am creating button dynamically. and creation action methods by
[newButton addTarget:self action:#selector(goToNew:)forControlEvents:UIControlEventTouchUpInside];
i want to send argument (indexpath.row) from tableview , but not want to use tag.. because i need that tag will remain same for all the buttons , how can i pass argument in button action ?
actually i am adding button in each tableview cell , and i want action for all those buttons , but if i use tag = indexpath.row and and use it with action, it works but problem of overlaying button happen.hence i want tag would be constant.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UIButton *btn;
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn addTarget:self action:#selector(goToNew:) forControlEvents:UIControlEventTouchUpInside];
btn.tag = 55;
[cell.contentView addSubview:btn];
}
else {
btn = (id)[cell.contentView viewWithTag:55];
}
return cell;
}
- (void) goToNew:(id)sender
{
UIButton *b = (UIButton *)sender;
UITableViewCell cell = (UITableViewCell)[b superview];
int row = [msgTableView indexPathForCell:cell].row;
(#"row is :::%d",row);
}
By doing following code, you will get the indexPath.row and no need to set the button tag.
- (IBAction)goToNew:(id)sender
{
UIButton *btn = (UIButton*) sender;
UITableViewCell *cell = (UITableViewCell*) [btn superview];
NSIndexPath *indexPath = [tableView indexPathForCell:cell];
int row = indexPath.row;
}
You can pass another argument as set title of button using different forstate.Here you can pass indexpath as title of button.like
btn.tag=10;
[btn setTitle:[NSString stringWithFormat:#"%d",indexpath.row] forState:UIControlStateDisabled];
[btn addTarget:self action:#selector(btnClick:)forControlEvents:UIControlEventTouchUpInside];
and you will received argument as
-(void)btnClick:(id)sender
{
UIButton* b = (UIButton*) sender;
NSLog(#"tag=%d",b.tag);
//Below line will got indexpath in string formate..
NSLog(#"title =%#",[b titleForState:UIControlStateDisabled]);
}
-(void)goToNew:(id)sender
{
UIButton *btnTemp = (UIButton *)[yourTableView viewWithTag:sender];
int iTag = btnTemp.tag;
}
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;
}