Siddharth
Siddharth

Reputation: 5219

How to animate and rotate a button

I have a UIButton and two UILabels around it. Right now, when you tap on the button, the two labels animate and inter-change their position. In addition to this happening, I want to animate and rotate the button 180 degrees and then back to the original position as the labels change position. How can I do this?

Here the code for the button click handler -

NSIndexPath *homeToWorkCellIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    UITableViewCell *homeToWorkCell = [self.tableView cellForRowAtIndexPath:homeToWorkCellIndexPath];
    UILabel *homeLabel = (UILabel *)[homeToWorkCell viewWithTag:1];
    UIButton *switchButton = (UIButton *)[homeToWorkCell viewWithTag:2];
    UILabel *workLabel = (UILabel *)[homeToWorkCell viewWithTag:3];

    CGRect homeLabelRectFrame = homeLabel.frame;
    CGRect workLabelRectFrame = workLabel.frame;

    [UIView animateWithDuration:0.3 animations:^{
        homeLabel.frame = workLabelRectFrame;
        workLabel.frame = homeLabelRectFrame;
    } completion:^(BOOL finished) {
        // will switch the pickup points here
        NSString *currentFromPickupPointId = _fromPickupPointId;
        NSString *currentToPickupPointId = _toPickupPointId;

        _fromPickupPointId = currentToPickupPointId;
        _toPickupPointId = currentFromPickupPointId;
    }];

I would ideally like to do this animation in this method but I do not have much experience in animations as I am new to iOS dev.

EDIT: As mentioned in the answers I tried changing my button tap handler to -

NSIndexPath *homeToWorkCellIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    UITableViewCell *homeToWorkCell = [self.tableView cellForRowAtIndexPath:homeToWorkCellIndexPath];
    UILabel *homeLabel = (UILabel *)[homeToWorkCell viewWithTag:1];
    UIButton *switchButton = (UIButton *)[homeToWorkCell viewWithTag:2];
    UILabel *workLabel = (UILabel *)[homeToWorkCell viewWithTag:3];

    CGRect homeLabelRectFrame = homeLabel.frame;
    CGRect workLabelRectFrame = workLabel.frame;

    // animation for the labels
    [UIView animateWithDuration:0.3 animations:^{
        homeLabel.frame = workLabelRectFrame;
        workLabel.frame = homeLabelRectFrame;
    } completion:^(BOOL finished) {
        // will switch the pickup points here
        NSString *currentFromPickupPointId = _fromPickupPointId;
        NSString *currentToPickupPointId = _toPickupPointId;

        _fromPickupPointId = currentToPickupPointId;
        _toPickupPointId = currentFromPickupPointId;
    }];

    // animation block for the button
    [UIView animateWithDuration:0.3/2 delay:0 options:UIViewAnimationOptionAutoreverse animations:^{
        CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI);
        switchButton.transform = transform;
    }completion:^(BOOL finished) {
        CGAffineTransform transform = CGAffineTransformMakeRotation(0);
        switchButton.transform = transform;
    }];

This does animate the button rotation. But the animation of the interchange of the labels does not happen anymore. Not sure what is happening here.

Please let me know if something in not clear in the comments.

Upvotes: 1

Views: 1970

Answers (2)

staticVoidMan
staticVoidMan

Reputation: 20234

Use this animation block for the button alongwith the rest of your code:

[UIView animateWithDuration:0.3/2 //half the label animation duration
                      delay:0
                    options:UIViewAnimationOptionAutoreverse
                 animations:^{
                     CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI);
                     switchButton.transform = transform;
                 }
                 completion:^(BOOL finished) {
                     CGAffineTransform transform = CGAffineTransformIdentity;
                     switchButton.transform = transform;
                 }];

EDIT:

If you're interchanging the the labels by frame then remove AutoLayout on your custom UITableViewCell (Xib > File Inspector > (Uncheck) Use Autolayout)

But...

If want to continue using AutoLayout on the UITableViewCell, and you should, then you need to change the label constraints rather than the frame.

To do it via Constraint changes:

  1. Put constraints on the views
  2. Make Outlet connections for the necessary constraints with NSLayoutConstraint objects
  3. Modify the constraint's constant parameter
  4. Call -layoutIfNeeded on the view that holds these constraints

Example (in Autolayout via XIB):

In the .h of your Custom UITableViewCell class (that I've named CustomCell)

@interface CustomCell : UITableViewCell

@property (nonatomic, strong) IBOutlet UIButton *btnTest;
@property (nonatomic, strong) IBOutlet UITextField *txtF_1;
@property (nonatomic, strong) IBOutlet UITextField *txtF_2;

//----txtF_1 constraints
//Leading Constraint
@property (nonatomic, strong) IBOutlet NSLayoutConstraint *constraint_1_left;
//Trailing Constraint
@property (nonatomic, strong) IBOutlet NSLayoutConstraint *constraint_1_right;

//----txtF_2 constraints
//Leading Constraint
@property (nonatomic, strong) IBOutlet NSLayoutConstraint *constraint_2_left;
//Trailing Constraint
@property (nonatomic, strong) IBOutlet NSLayoutConstraint *constraint_2_right;

@end

Example XIB looks like:

XIB


Connecting an NSLayoutConstraint outlet:

Constraint Outlet


txtF_1 Constraints Overview:

txtF_1


txtF_2 Constraints Overview:

txtF_2


Your tableViewController methods

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        cell = [[[NSBundle mainBundle] loadNibNamed:@"CustomCell"
                                              owner:nil
                                            options:nil]
                objectAtIndex:0];
    }

    [cell.txtF_1 setText:@"left"];
    [cell.txtF_2 setText:@"right"];

    [cell.btnTest addTarget:self
                     action:@selector(btnTestAct:event:)
           forControlEvents:UIControlEventTouchUpInside];

    return cell;
}

-(void)btnTestAct:(UIButton *)sender event:(UIEvent *)event
{
    NSSet *touches = [event allTouches];
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:point];

    CustomCell *cell = (CustomCell *)[self.tableView cellForRowAtIndexPath:indexPath];

    //backup constraints
    NSInteger i_left = cell.constraint_1_left.constant;
    NSInteger i_right = cell.constraint_1_right.constant;
    //swap constraints
    cell.constraint_1_left.constant = cell.constraint_2_left.constant;
    cell.constraint_1_right.constant = cell.constraint_2_right.constant;
    cell.constraint_2_left.constant = i_left;
    cell.constraint_2_right.constant = i_right;

    CGFloat f_animationTime = 0.3;

    //textField animation
    [UIView animateWithDuration:f_animationTime
                     animations:^{
                         //animate constraint changes
                         [self.view layoutIfNeeded];
                     }];

    //button animation
    [UIView animateWithDuration:f_animationTime/2
                          delay:0
                        options:UIViewAnimationOptionAutoreverse
                     animations:^{
                         CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI);
                         sender.transform = transform;
                     }
                     completion:^(BOOL finished) {
                         CGAffineTransform transform = CGAffineTransformIdentity;
                         sender.transform = transform;
                     }];
}

Upvotes: 3

Gal Marom
Gal Marom

Reputation: 8629

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.35];
button.transform = CGAffineTransformMakeRotation(degreesToRadians(45));

[UIView commitAnimations];

don't forget to define: #define degreesToRadians(degrees) (M_PI * degrees / 180.0)

Upvotes: 0

Related Questions