Animate UIView height from bottom to top

2019-03-11 11:12发布

问题:

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

回答1:

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.



回答2:

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;
}


回答3:

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



回答4:

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.



回答5:

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"];
}


回答6:

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];