问题
I have two blocks of code, one working and the second not really. The first adds a view, constraints its height to 0 and then cancel this constraint in an animation block so it grows up. Works perfect. The second one is supposed to reactivate the 0 height constraint
so that its height shrinks back to 0 and then remove it, but instead it is removed instantaneously. Here's the code:
self.pickupAddressViewModel.infoViewBlock = ^(MandatoryPickupView * _Nonnull pickupView) {
if (weakSelf.mandatoryPickupView) {
return;
}
weakSelf.mandatoryPickupView = pickupView;
[weakSelf.view addSubview:pickupView];
CGFloat gap = weakSelf.orderButton.originY;
[[pickupView.bottomAnchor constraintEqualToAnchor:weakSelf.view.bottomAnchor constant:-gap] setActive:YES];
[[pickupView.leadingAnchor constraintEqualToAnchor:weakSelf.view.leadingAnchor
constant:16.0] setActive:YES];
[[pickupView.trailingAnchor constraintEqualToAnchor:weakSelf.view.trailingAnchor
constant:-16.0] setActive:YES];
weakSelf.mandatoryPickupViewHeight = [pickupView.heightAnchor constraintEqualToConstant:0];
[weakSelf.mandatoryPickupViewHeight setActive:YES];
[weakSelf.view layoutIfNeeded];
[UIView animateWithDuration:0.5 animations:^{
[weakSelf.mandatoryPickupViewHeight setActive:NO];
[weakSelf.view layoutIfNeeded];
}];
};
self.pickupAddressViewModel.closeViewBlock = ^{
if (!weakSelf.mandatoryPickupView) {
return;
}
[weakSelf.view layoutIfNeeded];
[UIView animateWithDuration:10.5
animations:^{
[weakSelf.mandatoryPickupViewHeight setActive:YES];
[weakSelf.view layoutIfNeeded];
} completion:^(BOOL finished) {
[weakSelf.mandatoryPickupView removeFromSuperview];
weakSelf.mandatoryPickupView = nil;
weakSelf.mandatoryPickupViewHeight = nil;
}];
};
- It's all happening on the main thread.
- I tried settings the frame's height to 0 instead, also didn't work
weakSelf.mandatoryPickupViewHeight
is a strong property and it is not nil when I activated the second time.
Any suggestions? Thanks!
回答1:
When you are using autolayout for animations, you do it as follows:
Make sure autolayout is done:
self.view.layoutIfNeeded()
Then you change the constraints BEFORE the animation block. So for example:
someConstraint.constant = 0
Then after changing the constraint, you tell the autolayout that constraints have been changed:
self.view.setNeedsLayout()
And then you add an animation block with simply calling
layoutIfNeeded()
:UIView.animate(withDuration: 1, animations: { self.view.layoutIfNeeded() })
Notice that you don't deactivate the constraint - it has to be active the whole time.
I guess that in your code the problem is here:
[UIView animateWithDuration:0.5 animations:^{
[weakSelf.mandatoryPickupViewHeight setActive:NO];
[weakSelf.view layoutIfNeeded];
}];
Try changing it to
[weakSelf.mandatoryPickupViewHeight setActive:NO];
[weakSelf.view setNeedsLayout];
[UIView animateWithDuration:0.5 animations:^{
[weakSelf.view layoutIfNeeded];
}];
Although what you are doing seems a bit obscure. If the constraint is deactivated, are you sure the autolayout has enough constraints to calculate the proper height? If so, are you sure that mandatoryPickupViewHeight
constraint is not in collision with those?
回答2:
This is the methodology to shrink a view to zero height and to make it grows as height as of it's subviews.
-(void)manageViewCollapse
{
if(animationRunning)
{
return ;
}
animationRunning = YES;
if(supportShown)
{
// Hide the view by setting its height constant to zero
NSLayoutConstraint*full=[NSLayoutConstraint constraintWithItem:self.supportView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:0.0];
[self.supportView addConstraint:full];
// retrieve the bottom constraint of the view with bottom most item and remove it
for (NSLayoutConstraint*con in self.supportView.constraints)
{
if (con.firstAttribute == NSLayoutAttributeBottom && con.firstItem == self.bottomItemView)
{
[self.supportView removeConstraint:con];
break;
}
}
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
}completion:^(BOOL finished){
supportShown = NO;
animationRunning = NO ;
} ];
}
else
{
// show the view first by deleting it's zero height
for (NSLayoutConstraint*con in self.supportView.constraints)
{
if (con.firstAttribute == NSLayoutAttributeHeight)
{
[self.supportView removeConstraint:con];
break;
}
}
// hook the bottom of the view again to the bottom most item to make it have the correct height
NSLayoutConstraint*full1=[NSLayoutConstraint constraintWithItem:self.bottomItemView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.supportView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-15.0];
full1.priority = UILayoutPriorityDefaultHigh;
[self.supportView addConstraint:full1];
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
}completion:^(BOOL finished){
supportShown = YES;
animationRunning = NO;
} ];
}
}
来源:https://stackoverflow.com/questions/48091661/objective-c-animating-height-constraint-change-not-working