I'm trying to delete cell with a Button.
Here is the implementation of a cell.
- (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];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.frame = CGRectMake(0.f, 0.f, 30.f, 30.f);
[btn addTarget:self
action:#selector(btnTouched:)
forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:btn];
cell.tag = indexPath.row;
}
return cell;
}
- (void)btnTouched:(UIButton *)sender
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:sender.tag inSection:0];
[_myMutableArray removeObjectAtIndex:sender.tag];
[_tableView beginUpdates];
[_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationLeft];
[_tableView endUpdates];
}
This works well until I've delete a row, the button isn't reloaded so after a delete, I don't delete the good index. I tried to put reloadRowsAtIndexPaths:withRowAnimation: for visible indexPath after the endUpdates method and it works very well. But the delete animation became ugly by the reloadRows animation (even if I set it to NO).
So is there a way to reload cells without reloadCellsAtIndexPath. Or delete a rows without using tags.
Thx a lot.
You should be able to lookup the index of the cell by using logic similar to the following:
NSIndexPath *indexPath = [_tableView indexPathForCell:(UITableViewCell *)[sender superview]];
With this approach, you would not need to store the value of the row index in the cell tag.
To just reload the table (and thus all its cells), you could try just using:
[_tableView reloadData];
Related
I am a newbie to iPhone programming. I am stuck in a situation. I need to change the UITableViewCell image (on the left side) through calling an action from UIBarButtonItem fromt he UIToolBar. I have searched through internet, but can't find any appropriate solution.
Any Help regarding this would be appreciated.
Here is a sample code for customizing cell imageView.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"MyTableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
[cell.imageView setBounds:CGRectMake(0, 0, 30, 30)];
[cell.imageView setClipsToBounds:YES];
[cell.imageView setFrame:CGRectMake(0, 0, 30, 30)];
[cell.imageView setContentMode:UIViewContentModeScaleAspectFit];
}
// customize cell
[cell.imageView setImage:**your_image**];
return cell;
}
With the [tableview cellForRowAtIndexPath:] method you can access a cell at a specific row. When you have accessed that you can reach the image by cell.imageView. Have a look at this:
- (IBAction)barbuttonPressed
{
UITableViewCell *cell = [self.tableView [NSIndexPath indexPathForRow:row inSection:section];
cell.imageView = .....
}
Replace row and section with appropriate.
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;
}
In my UITableView, i need to get the event of the user, so when the cell is selected(checked), i put btn_checked.png and when it's unchecked, i put the btn_unchecked.png.
I guess, what i try to do should be in the didSelectRowAtIndexPath method, so this is my code:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *listData =[self->tableContents objectForKey:
[self->sortedKeys objectAtIndex:[indexPath section]]];
UITableViewCell* theCell = [tableView cellForRowAtIndexPath:indexPath];
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"btn_unchecked.png"]];
theCell.accessoryView = imageView;
}
My snippet code doesn't work, so the btw_unchecked.png isn't placed when the row is checked, also, i need to get the event of checked/unchecked to place the right image to the right event.
Thanx in advance.
As an example, this code snippet will toggle the cell's checkmark when the cell is tapped. The pattern is to force a selective reload from the table's datasource when the delegate method is invoked.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Dequeue the cell... then:
static NSString *CellIdentifier = #"tvcOEList";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.accessoryType = (cell.accessoryType == UITableViewCellAccessoryNone) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
}
You can use following code.
[cell.contentView addSubview:imageView];
i hope this will help you..
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
}
in my application I have UITableView & i used
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
and when I scrolled this table then I get multiple checkmark in multiple cell
please help me..
In general, the cell come from 2 ways:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"Cell";
UITableViewCell *cell = ... // The cell come from reuse queue.
if (cell == nil) {
cell = ... // if reuse queue has no cell, then create an autoreleased cell
}
// Configure cell by indexPath.
// You should configure cell HERE.
}
Because your cell maybe come from reuse queue, it was configured. Obviously, you forget to re-configure those cells which come from reuse queue.
you can use this sample code on tableView's delegate method didSelectedRowAtIndexPath
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[cell setSelected:YES animated:YES];
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
for(int iterator=0;iterator<3;iterator++)
{
UITableViewCell *eachCell = [[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:iterator inSection:0]];
[eachCell setSelected:NO animated:YES];
[eachCell setAccessoryType:UITableViewCellAccessoryNone];
}
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
[newCell setSelected:YES animated:YES];
[newCell setAccessoryType:UITableViewCellAccessoryCheckmark];