bandejapaisa
bandejapaisa

Reputation: 26952

Animate UIView height from bottom to top

I'm doing a simple animation of UIView height so that it reveals.

By default it seems to be revealing from top to bottom, and I want it to reveal bottom to top.

I have the UIView anchored to the bottom of the screen.

I'm sure it something simple i'm missing..... any tips?

Thanks

Upvotes: 13

Views: 30425

Answers (6)

bandejapaisa
bandejapaisa

Reputation: 26952

Like a dog with a bone I figured this out....

Instead of animating the frame height, I applied a transform to the view and set the anchor point of the layer.

//set the anchor point to the bottom of the view
[self setAnchorPoint:CGPointMake(0.5, 1.0) forView:hostView];
//Scale the height to close to zero
hostView.transform = CGAffineTransformMakeScale(1, 0.00001);

If I put 0 as the y scale, the view behaves weird.... at the end of the animation i just set it to hidden.

On the way back up I just use the Identity Transform (reset it)

hostView.transform = CGAffineTransformIdentity;

Note that changing my anchor point shifted the position of my view. See this post for the setAnchorPoint method which normalises the view after setting the anchorPoint

Changing my CALayer's anchorPoint moves the view

Upvotes: 5

Warif Akhand Rishi
Warif Akhand Rishi

Reputation: 24248

hide under bottom

[self animateViewHeight:myView withAnimationType:kCATransitionFromBottom];

for reverse animation

[self animateViewHeight:myView withAnimationType:kCATransitionFromTop];

...

- (void)animateViewHeight:(UIView*)animateView withAnimationType:(NSString*)animType {  
    CATransition *animation = [CATransition animation];
    [animation setType:kCATransitionPush];
    [animation setSubtype:animType];

    [animation setDuration:0.5];
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
    [[animateView layer] addAnimation:animation forKey:kCATransition];
    animateView.hidden = !animateView.hidden;
}

Upvotes: 10

timbroder
timbroder

Reputation: 878

one way I've done it with an AdWhirlView, hide it below the screen, then animate it up;

AdWhirlView *adWhirlView = [AdWhirlView requestAdWhirlViewWithDelegate:self];
adWhirlView.delegate = self;
adWhirlView.frame = CGRectMake(0, 430+kAdWhirlViewHeight, kAdWhirlViewWidth, kAdWhirlViewHeight);
[self.parentViewController.view insertSubview:adWhirlView belowSubview:self.view];

[UIView beginAnimations:@"AdWhirlIn" context:nil];
[UIView setAnimationDuration:.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
adWhirlView.frame = CGRectMake(0, 430, kAdWhirlViewWidth, kAdWhirlViewHeight);
[UIView commitAnimations];

Upvotes: 0

atreat
atreat

Reputation: 4413

I really think the simplest way to accomplish this would be to animate BOTH the height and the y properties of the view. If they happen along the same curve, it should look completely seamless to the user. As you are animating the height to 0, also animate the y component to the original y + the original height.

UIView *view = ...;
float originalY = view.frame.origin.y;
float originalH = view.bounds.size.height;

[UIView animateWithDuration:1.2f delay:1.0f options:UIViewAnimationCurveEaseInOut animations:^{
    view.frame = CGRectMake(view.frame.origin.x, (originalY + originalH), view.bounds.size.width, 0);

}completion:^(BOOL finished) {
    NSLog(@"Animation is complete");
}];

I believe this would give the look and feel of a collapsing view. I haven't tried this out in code, but I see no reason why it wouldn't be possible like this.

Upvotes: 11

aleph_null
aleph_null

Reputation: 5786

As requested, this is the code that I'm using... I'm using a CAKeyFrameAnimation, which may be a bit more than what you're looking for. It would probably work the same with a CABasicAnimation, I'm just showing you this code because I already have it written.

-(id)initWithFrame:(CGRect)frame {
  self = [super initWithFrame:frame];
  if (self) {   
    springLayer = [[CALayer alloc] init];
    springLayer.backgroundColor = [UIColor redColor].CGColor;
    springLayer.anchorPoint = CGPointMake(0, 1);
    springLayer.frame = CGRectMake(125, 285, 100, 115);
    [springLayer setNeedsDisplay];
    [self.layer addSublayer:springLayer];
    [self test];
  }
  return self;
}

-(void)test {
    CAKeyframeAnimation *heightAnim = [[CAKeyframeAnimation alloc] init];
    heightAnim.duration = 3;
    heightAnim.removedOnCompletion = NO;
    heightAnim.fillMode = kCAFillModeForwards;

    heightAnim.beginTime = CACurrentMediaTime() + 0.25;

    NSMutableArray *v = [[NSMutableArray alloc] init];
    NSMutableArray *t = [[NSMutableArray alloc] init];

    float dest = 250;
    float difference = 135;


    while (difference > 1.0) {
        [v addObject:[NSNumber numberWithFloat:dest-difference]];
        [t addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];

        difference *= 0.7;

        [v addObject:[NSNumber numberWithFloat:dest+difference]];
        [t addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];

        difference *= 0.7;
    }

    heightAnim.values = v;
    heightAnim.timingFunctions = t;

    [springLayer addAnimation:heightAnim forKey:@"bounds.size.height"];
}

Upvotes: 2

aopsfan
aopsfan

Reputation: 2441

Instead you could try putting it in a view with clipsToBounds = YES and then animate it from the bottom to the middle of the view, like so:

viewToAnimate.frame = CGRectMake(viewToAnimate.frame.origin.x,
                                 viewToAnimate.superview.frame.size.height,
                                 viewToAnimate.frame.size.width,
                                 viewToAnimate.frame.size.height);

[UIView animateWithDuration:0.5 animations:^{
     viewToAnimate.center = viewToAnimate.superview.center;
}];

This way, you don't have to set the height to 0, and it solves any problems with autoresizing within the view.

Upvotes: 3

Related Questions