noobsmcgoobs
noobsmcgoobs

Reputation: 2746

Animate button on UITableViewCell without affecting other UITableViewCells

I have a UITableViewCell with the following code where a user clicks on the "Save" button on a UITableViewCell. The image in the cell is saved, and the "Save" button is animated away, but the cell remains.

   -(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

  if (!self.tableCell)
    {
        [tableView registerNib:[UINib nibWithNibName:@"LPContentTableViewCell" bundle:nil] forCellReuseIdentifier:@"ContentCell"];

        self.tableCell = [tableView dequeueReusableCellWithIdentifier:@"ContentCell"];
    }

        [self.tableCell.saveImageButton addTarget:self action:@selector(saveImage:) forControlEvents:UIControlEventTouchUpInside];

        return self.tableCell;

    }

    -(void)saveImage:(id)sender{

     UIButton *button = (UIButton*)sender;

    //image is saved

    [UIView animateWithDuration:0.5f animations:^{
            button.frame = newFrame;
        }completion:^(BOOL finished) {

                [button removeFromSuperview];


    }];

Problem is, the cells not allocated at the time I press save also lose their save buttons. I casted the button as the sender. The button is removed and the buttons on the next few cells remain. However, cells further down in the UITableView appear when I scroll without the button. Ideas?

EDIT: suggestions incorporated

UIButton * cellButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[cellButton setTitle:@"Save" forState:UIControlStateNormal];
[cellButton addTarget:self action:@selector(saveImage:) forControlEvents:UIControlEventTouchUpInside];
cellButton.frame = CGRectMake(268, 95, 79, 23);
[self.tableCell.contentView addSubview:cellButton];


-(void)saveImage:(id)sender{
UIButton *button = (UIButton*)sender;


CGRect newFrame = button.frame;

newFrame.origin.x +=100;

[UIView animateWithDuration:0.5f animations:^{
   button.frame = newFrame;

}completion:^(BOOL finished) {

        [button removeFromSuperview];

}];

Upvotes: 0

Views: 1730

Answers (3)

Krys Jurgowski
Krys Jurgowski

Reputation: 2911

You are breaking the MVC pattern with your implementation.

cellForIndexPath gets called whenever a cell is about to be presented on screen and should avoid needed to remember anything about your model (the images). Use indexPaths to get access to your model in methods.

The proper way to implement this is separate that out.

-(void) viewDidLoad
{
    [super viewDidLoad];

    // Register you nib here. You only need to do this once.
    [self.tableView registerNib:[UINib nibWithNibName:@"LPContentTableViewCell" bundle:nil] forCellReuseIdentifier:@"ContentCell"];
}

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Dequeuing will create or reuse cell. This is what that iOS silky smooth scrollin is all about
    LPContentTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ContentCell" forIndexPath: indexPath];

    BOOL canSave = YES; //figure out if image at indexPath can be saved..

    NSArray *targets = [cell.saveImageButton actionsForTarget:self forControlEvent:UIControlEventTouchUpInside];

    if ([targets count] == 0) {
        // Only add the target once per cell.. it would be easier to just add the target in IB instead of this method.
        [cell.saveImageButton addTarget:self action:@selector(saveImage:) forControlEvents:UIControlEventTouchUpInside];
    }


    if (canSave) {
        cell.saveImageButton.alpha = 1;
    }
    else {
        cell.saveImageButton.alpha = 0;
    }
}

-(void)saveImage:(id)sender {
    UIButton *button = (UIButton*)sender;
    LPContentTableViewCell *cell = [button superview];
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

    // Get image using indexPath and Save

    CGRect newFrame = button.frame;
    newFrame.origin.x +=100;

    [UIView animateWithDuration:0.5f animations:^{
       button.frame = newFrame;

    }completion:^(BOOL finished) {

        // Use alpha instead of removing the view so reused cells can just set the alpha back to 1
        button.alpha = 0;

        // Set the old frame back here too for reused cells.
        button.frame = oldFrame;
    }];
}

You LPContentTableViewCell's interface should look something like this.

@interface LPContentTableViewCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UIButton *saveImageButton;  // This needs to be connected with IB

@end

Upvotes: 3

TheSD
TheSD

Reputation: 883

You need to programmatically create a new button for every cell.

UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self 
        action:@selector(aMethod:)
forControlEvents:UIControlEventTouchUpInside];`

And you can add a tag to it as some type of identifier.

[button setTag:rowNumber];

Upvotes: 0

Ravi
Ravi

Reputation: 2451

try this..

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

  if (!self.tableCell)
    {
        [tableView registerNib:[UINib nibWithNibName:@"LPContentTableViewCell" bundle:nil] forCellReuseIdentifier:@"ContentCell"];

        self.tableCell = [tableView dequeueReusableCellWithIdentifier:@"ContentCell"];
    }

           UIButton * cellButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
          [cellButton setTitle:@"Save" forState:UIControlStateNormal];
          [cellButton addTarget:self action:@selector(saveImage:) forControlEvents:UIControlEventTouchUpInside];
          cellButton.frame = CGRectMake(127, 8, 50, 30);
          [cell.contentView addSubview:cellButton];

        return self.tableCell;

    }

    -(void)saveImage:(UIButton*)sender{

    //image is saved

    [UIView animateWithDuration:0.5f animations:^{

        }completion:^(BOOL finished) {

                [sender removeFromSuperview];


    }];

Upvotes: 0

Related Questions