-1

I have two UIViews I would like to animate on screen and off. Both should start positioned off screen. The top animates downward, bottom upward. Without constraints it works as expected. But with, the UIViews are visible at app launch (with a slight animation that is visible). They do animate off screen though.

For the top UIView, I have a Leading Space, Trailing Space, Top Space, and Height.

For the bottom UIView, I have a Leading Space, Trailing Space, Bottom Space, and Height.

How should I adjust my code and/or constraints to get the desired animation?

Here is my code:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self animateViewsIn];
}

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];

    self.topView.frame = CGRectMake(16.0, -self.topView.frame.size.height, self.topView.frame.size.width, self.topView.frame.size.height);

    self.bottomView.frame = CGRectMake(16.0, self.view.bounds.size.height, self.bottomView.frame.size.width, self.bottomView.frame.size.height);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)animateViewsIn {
    [UIView animateWithDuration:0.5
                      delay:1.0
                    options: UIViewAnimationOptionCurveEaseIn
                 animations:^{
                     self.topView.frame = CGRectMake(16.0, 
    self.topView.frame.size.height/8.0, self.topView.frame.size.width, 
    self.topView.frame.size.height);
                     self.bottomView.frame = CGRectMake(16.0, (self.view.bounds.size.height-self.bottomView.frame.size.height)-20.0, self.bottomView.frame.size.width, self.bottomView.frame.size.height);
                 }
                 completion:^(BOOL finished){
                     NSLog(@"Done!");
                 }];
}

- (IBAction)animateViewsOut:(id)sender {
    CGRect basketTopFrame = self.topView.frame;
    basketTopFrame.origin.y = -basketTopFrame.size.height;

    CGRect basketBottomFrame = self.bottomView.frame;
    basketBottomFrame.origin.y = self.view.bounds.size.height;


    [UIView animateWithDuration:0.5
                      delay:1.0
                    options: UIViewAnimationOptionCurveEaseOut
                 animations:^{
                     [self.view layoutIfNeeded];

                     self.topView.frame = basketTopFrame;
                     self.bottomView.frame = basketBottomFrame;
                 }
                 completion:^(BOOL finished){
                     NSLog(@"Done!");
                 }];
}
Luke Irvin
  • 1,179
  • 1
  • 20
  • 39
  • When using constraints, you should not be adjusting frames. You should be modifying the `constant` property of the constraint (or deactivinging one constraint and activating another). Possible duplicate of https://stackoverflow.com/a/28329399/1271826 (tho, admittedly Swift answer; the idea is identical in Objective-C). Or here is Objective-C answer that illustrates the animation of constraints: https://stackoverflow.com/a/14190042/1271826. – Rob Sep 10 '17 at 19:07
  • Thank you Rob. I have added the constraints connected via IBOutlet and using the constant to animate them, but how do I start the UIViews off-screen? – Luke Irvin Sep 10 '17 at 19:34
  • leftConstraint.constant - 320. is example how to start offscreen. – GeneCode Sep 11 '17 at 00:58

1 Answers1

1

When using constraints, you should not be adjusting frames. You should be modifying the constant property of the constraint (or deactivinging one constraint and activating another).

Here's an example of animating the top view in from the top, assuming you added a @IBOutlet called topConstraint to the top constraint of the view topView:

In Objective-C:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    self.topConstraint.constant = -self.topView.frame.size.height;  // or whatever you want
    [self.view layoutIfNeeded];
    [UIView animateWithDuration:0.5 delay:1 options:0 animations:^{
        self.topConstraint.constant = 0;
        [self.topView layoutIfNeeded];
    } completion:nil];
}

In Swift:

override func viewDidAppear(_ animated: Bool) {
    topConstraint.constant = -topView.frame.height  // or whatever you want
    view.layoutIfNeeded()
    UIView.animate(withDuration: 0.5, delay: 1, animations: {
        topConstraint.constant = 0
        self.view.layoutIfNeeded()
    })
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044