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

StackOverflow https://stackoverflow.com/questions/18112769

質問

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top