How to animate the width and height of a UIView in Xcode?

45,585

Solution 1

To make a view "grow" into place, don't animate the frame. Animate the transform.

Load your subview from the nib. Set its transform to a scale of 0:

view.transform = CGAffineTransformMakeScale(0,0);

Then add it to your superview.

Inside the animation block, set the transform to identity:

view.transform = CGAffineTransformIdentity;

And the view will grow to normal size. You may need to fiddle with the anchor point to make it grow from the right point.

You can also change the frame within the block, but to move a view only I prefer to change the center property, you shouldn't try to set the frame if you also have a transform.

For bonus points, you can also animate to a slightly bigger than 1.0 scale, then animate back to the identity transform in a chained animation from the completion block. This makes the view "pop" out of the screen like an alert view.

Solution 2

Try using a block it will be more clear.

 // First create the view if you haven't already 
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)]; 
// Add it as a subview. 
[myViewController.view addSubview:myView]; 


CGRect newFrameOfMyView = CGRectMake(0.0f, 0.0f, 200.0f, 200.0f); 
/*
 * Alternatively you could just set the width/height or whatever you'd like with this: 
 * CGRect newFrameOfMyView = myView.frame; 
 * newFrameOfMyView.size.height = 200.0f; 
 * newFrameOfMyView.size.width = 200.0f; 
 */
[UIView animateWithDuration:0.3f
     animations:^{
      myView.frame = newFrameOfMyView; 
     }
     completion:^(BOOL finished){ 
     NSLog( @"woo! Finished animating the frame of myView!" ); 
}];

Solution 3

Try this:

customView.frame= CGRectMake(self.view.frame.origin.x +5,self.view.frame.origin.y+5,0, 150);
[self.view addSubview:customView];
CGRect frame = customView.frame;
frame.size.width = 310;
[UIView animateWithDuration:0.4
 animations:^{
  customView.frame= frame; 
 }];

Or if you want to use beginAnimation method instead of block Methos , Use this :

UIView *customView=[[UIView alloc]initWithFrame:CGRectMake(self.view.frame.origin.x +5,self.view.frame.origin.y+5,0, 150)];
[self.view addSubview:customView];
CGRect frame = customView.frame;
frame.size.width = 310;
[UIView beginAnimations:@"animateAddContentView" context:nil];
[UIView setAnimationDuration:0.4];
customView.frame= frame;
[UIView commitAnimations];

Solution 4

Here is a fun way of animating your views. In my example I have a touch action that will execute the block animations and a BOOL to make sure to reset the views back to their original states.

First you put 2 UIViews on a UIViewController (you can color them different colors for contrast). Connect them to your "MainViewController.h" file you create to control the big view. The .h file should look like this:

#import <UIKit/UIKit.h>

@interface MainViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIView *topView;
@property (weak, nonatomic) IBOutlet UIView *bottomView;

@end

and your .m file should look like this:

#import "MainViewController.h"
#define kViewAnimateWithDuration 0.35f
#define kViewDelay 0.05f

@interface MainViewController ()
@property (nonatomic) BOOL setTouch;
@end

@implementation MainViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
        self.setTouch = NO;
    }
    return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    UITouch *touch = [touches anyObject];
    CGPoint touchLocation = [touch locationInView:self.view];

    float width_tp = self.topView.frame.size.width;
    float height_tp = self.topView.frame.size.height;

    float width_b = self.bottomView.frame.size.width;
    float height_b = self.bottomView.frame.size.height;

    if ((CGRectContainsPoint(self.bottomView.frame, touchLocation)) && !self.setTouch){

        [UIView animateWithDuration:kViewAnimateWithDuration
                              delay:kViewDelay
                            options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
                         animations:^{
                             //Move frame or transform view
                             [self.topView setFrame:CGRectMake(self.topView.frame.origin.x, self.topView.frame.origin.y, width_tp, height_tp + 171)];

                             [self.bottomView setFrame:CGRectMake(self.bottomView.frame.origin.x, self.bottomView.frame.origin.y +171, width_b, height_b -171)];

                         } completion:^(BOOL finished) {
                             self.setTouch = YES;
                         }];



    }
    if ((CGRectContainsPoint(self.bottomView.frame, touchLocation)) && self.setTouch) {
        [UIView animateWithDuration:kViewAnimateWithDuration
                              delay:kViewDelay
                            options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
                         animations:^{
                             //Move frame or transform view
                             [self.topView setFrame:CGRectMake(self.topView.frame.origin.x, self.topView.frame.origin.y, width_tp, height_tp - 171)];

                             [self.bottomView setFrame:CGRectMake(self.bottomView.frame.origin.x, self.bottomView.frame.origin.y -171, width_b, height_b +171)];

                         } completion:^(BOOL finished) {
                             self.setTouch = NO;
                         }];
    }

}

So just make sure the topView has some small dimensions like x:0,y:0 width:320 height:43 and bottomView like x:0 y:40 width:320 height:528. Remember to color the backgrounds different colors. Then just run the program and you should see animations.

For me I think one of the more important lines in the code is setFrame: that to me enables the frame to automagically redisplays the rectangle without having to use the DrawRect method. Setting the property changes the point specified by the center property and the size in the bounds rectangle accordingly.

Of course there are other fun ways to do this but I hope this can help someone make iOS look magical like it is supposed to be! Happy journeys!

Solution 5

Swift 4

  UIView.animate(withDuration: 0.3, animations: {
        self.whiteBackgroundView.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
        self.view.layoutIfNeeded()
    }) { (finished) in
        // end of animation
    }
Share:
45,585
Hudson Buddy
Author by

Hudson Buddy

Updated on July 12, 2022

Comments

  • Hudson Buddy
    Hudson Buddy almost 2 years

    I have this subview I want to add to my main view, but make it expand from the origin. I read some of the Apple documentation but I don't understand where I am making mistake. I can animate the origin of the frame, i.e. to get it slide in from wherever, but the width/height doesn't seem to animate. Code as follows:

    [UIView beginAnimations:@"animateAddContentView" context:nil];
    [UIView setAnimationDuration:0.4];
    customView.frame= CGRectMake(self.view.frame.origin.x +5, self.view.frame.origin.y +5, 0, 150);
    [self.view addSubview:customView];
    
    customView.frame= CGRectMake(self.view.frame.origin.x +5, self.view.frame.origin.y +5, 310, 150);
    [UIView commitAnimations];
    

    I have also tried putting only the setFrame part in the animation like this:

    customView.frame= CGRectMake(self.view.frame.origin.x +5, self.view.frame.origin.y +5, 0, 150);
    [self.view addSubview:customView];
    [UIView beginAnimations:@"animateAddContentView" context:nil];
    [UIView setAnimationDuration:0.4];
    customView.frame= CGRectMake(self.view.frame.origin.x +5, self.view.frame.origin.y +5, 310, 150);
    [UIView commitAnimations];
    

    But it still doesn't work!

    EDIT:

    As per the suggestions, I have moved it to a block based animation solution, and this is the exact code:

    NSLog(@"yourview : %@",customView);
    customView.frame= CGRectMake(self.view.frame.origin.x +5, self.view.frame.origin.y +5, 0, 150);
    
    NSLog(@"yourview : %@",customView);
    [self.view addSubview:customView];
    NSLog(@"yourview : %@",customView);
    
    //    [customView setFrame:CGRectMake( 0.0f, 480.0f, customView.frame.size.width, customView.frame.size.height)];
    
    [UIView animateWithDuration:0.4
                          delay:0
                        options:UIViewAnimationCurveEaseInOut
                     animations:^ {
                         NSLog(@"yourview : %@",customView);
    
                         customView.frame = CGRectMake(self.view.frame.origin.x +5, self.view.frame.origin.y +5, 310, 150);
                         NSLog(@"yourview : %@",customView);
    
                     }completion:^(BOOL finished) {
    
                     }];
    

    Which still doesn't work for some reason. Possible problems I see are:

    1. I am loading this customView from a nib that is specifically 310 by 150, perhaps that is causing a problem.
    2. I am not importing the correct frameworks, but since I can animate the frame.origin parts of this view, I am not sure that is the case...I have QuartzCore and Core Graphics all imported and stuff.

    At each point in the log it is giving the correct stuff: for example, before the target frame the size is 0, 150, and after I set the frame its 310, 150. But the animation doesn't work!