简体   繁体   中英

Animate UIImageView from center to 20 points from the top of parent UIView using AutoLayout

The animation by itself works when I use a constraint on the distance between the UIImageView and the top of the parent UIView without vertical and horizontal centering.

The constraints on the UIImageView:

  • Width: 240
  • Height: 128
  • Top space to Top Layout: 200 --> connected to logoImageViewVerticalSpaceConstraint

The animation works great when I use this:

self.logoImageViewVerticalSpaceConstraint.constant = 20;

[UIView animateWithDuration: 1.0
                      delay: 0
                    options:(UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionAllowUserInteraction)                     
                 animations:^{[self.logoImageView layoutIfNeeded];}
                 completion:^(BOOL finished) {NSLog(@"Finished animation"); }];

The issue kicks in when I don't want to use a static space to top layout constraint because the imageview needs to be centred for 3.5 and 4 inch devices. To solve this I thought starting off with a vertical and horizontal center constraint.

  • Width: 240
  • Height: 128
  • Align center x to: superview --> connected to logoImageViewYCenterConstraint
  • Align center y to: superview

Now I thought I could simply remove the y center constraint and adding the space to top layout constraint of 20pt myself:

[self.logoImageView removeConstraint:self.logoImageViewYCenterConstraint];

NSLayoutConstraint *topSpaceConstraint = [NSLayoutConstraint  
constraintWithItem:self.view                                                                         attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual                                                                                    toItem:self.logoImageView
attribute:NSLayoutAttributeTop                                                                                multiplier:1
constant:20];
    [self.view addConstraint:topSpaceConstraint];

    [UIView animateWithDuration: 1.0
                          delay: 0
                        options:(UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionAllowUserInteraction)                     
                        animations:^{
                           [self.logoImageView layoutIfNeeded];
                        }
                        completion:^(BOOL finished) { 
                           NSLog(@"Finished animate"); 
                        }];

The result is that the UIImageView stays centred and it blows up a bit. Which is the total opposite of what I expect to happen because I removed the x center constraint. Added the top constraint with distance 20pt to the top of the parent UIView and I did not touch any other constraints (like the width and height).

An NSLayoutConstraint has one or two views that it constrains. In your case, the views are self.logoImageView and self.view .

To have any effect, the constraint must be installed on a view, and not just any view. The constraint must be installed on a common ancestor of both constrained views . (Note that a view is considered to be an ancestor of itself.) And when you remove a constraint, you must remove it from the view on which it is installed .

You're trying to remove the centering constraint from self.logoImageView , but the constraint can't have been installed on that view.

As of iOS 8.0, the preferred (and easiest) way to uninstall a constraint is to set its active property to NO :

self.logoImageViewYCenterConstraint.active = NO;

Prior to iOS 8.0, you have to remove it from the view where it's installed. The constraint is probably installed on self.view . So try this instead:

[self.view removeConstraint:self.logoImageViewYCenterConstraint];

Note also that if you want to animate the image view back to the center, you'll need to uninstall topSpaceConstraint and reinstall self.logoImageViewYCenterConstraint .

A different way to handle this is to install both constraints simultaneously, but give one of them a lower priority. When you need to change the position of the image view, change the priorities of the constraints. Thus:

- (void)viewDidLoad {
    [super viewDidLoad];
    if (self.topSpaceConstraint == nil) {
        self.topSpaceConstraint = [NSLayoutConstraint constraintWithItem:...];
        self.topSpaceConstraint.priority = 1;
        [self.view addConstraint:self.topSpaceConstraint];
    }
}

- (void)setImageViewCenteredVertically:(BOOL)isCentered animated:(BOOL)animated {
    if (isCentered) {
        self.topSpaceConstraint.priority = 1;
        self.logoImageViewYCenterConstraint.priority = UILayoutPriorityRequired;
    } else {
        self.topSpaceConstraint.priority = UILayoutPriorityRequired;
        self.logoImageViewYCenterConstraint.priority = 1;
    }

    if (animated) {
        [UIView animateWithDuration:1 delay:0
            options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
            animations:^{
                [self.view layoutIfNeeded];
            }
            completion:nil];
    }
}

I'm not really a master of NSLayoutConstraints , but either you should add the constraint to the logoImageView object or you should change the constraintWithItem: parameter because to me something looks strange right now. You're removing a constraint from the imageView, then adding a constraint to the self.view object which refers to self.view item

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM