Animate autoLayout constraints doesn't work on iOS 7 - ios

I have an UIButton that has only 4 constraints related to its height,width, top, left.
When the user tap on the button i update its top constraint by adding a constant value like this
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.4 animations:^{
[self updateMyButtonConstraints];
[self.view layoutIfNeeded];
}];
-(void)updateMyButtonConstraints {
myTopButtonConstraint.constant = 10;
}
When i run my app on iOS 8 its works like a charm, but on iOS 7 the constraint animation doesn't work, the button basically moves from point a to point b without any animation
PS : i tried to put the update constraint instruction before starting the animation and its didn't work too
How can i do to fix this ? What i'm doing wrong ? thank you for the help

You're doing things in the wrong order, and you're forgetting to notify the layout system that layout is needed. Like this:
[self updateMyButtonConstraints];
[self.view setNeedsLayout]; // not "layoutIfNeeded"!
[UIView animateWithDuration:0.4 animations:^{
[self.view layoutIfNeeded];
}];
In my tests, that animates in iOS 7, iOS 8, and iOS 9. If it doesn't work for you, you're doing something else that you have not revealed.

Swift version is here.
self.updateMyButtonConstraints()
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.4) {
self.view.layoutIfNeeded()
}

Related

How can I animate the height constraint of a UIPickerView?

I've learned that the way to animate constraints in Cocoa Touch is to just set them and then put [self.view layoutIfNeeded] in an animation block, like so:
self.someViewsHeightConstraint = 25.0;
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
}];
This is working fine, for example with a simple UIView. However, it does not work with a UIPickerView. It just snaps into the new position without animating.
Any ideas why this might be the case? What ways are there to work around this?
The effect I'm going for is that the Picker View should shrink to just show the chosen item, as the user goes on to input other things. One idea I had is to make a snapshotted view and animate that instead, but I couldn't quite get that working either.
I found trying to animate the height or the placement constraint of a UIPickerView to be problematic. However, doing transforms seems to work well -- even if you have Auto Layout Constraints everywhere, including in the view to be transformed.
Here's an example of what works for me. In this case, I've placed the picker view inside a blurring effects view -- but you don't even need to put your picker view inside another view to animate it.
In the code below, when I call show, it animates up vertically. When I call the hide method, it animates downwards.
- (void)showPickerViewAnimated:(BOOL)animated;
{
__weak MyViewController *weakSelf = self;
[UIView animateWithDuration:(animated ? kPickerView_AppearanceAnimationDuration : 0.0)
delay:(animated ? kPickerView_AppearanceAnimationDelay : 0.0)
options:(UIViewAnimationOptionCurveEaseInOut)
animations:^{
weakSelf.pickerViewContainerView.transform = CGAffineTransformMakeTranslation(0,0);
}
completion:^(BOOL finished) {
[weakSelf.view layoutIfNeeded];
}];
}
- (void)hidePickerViewAnimated:(BOOL)animated;
{
__weak MyViewController *weakSelf = self;
[UIView animateWithDuration:(animated ? kPickerView_DisappearanceAnimationDuration : 0.0)
delay:(animated ? kPickerView_DisappearanceAnimationDelay : 0.0)
options:(UIViewAnimationOptionCurveEaseInOut)
animations:^{
weakSelf.pickerViewContainerView.transform = CGAffineTransformMakeTranslation(0, kPickerView_Height);
}
completion:^(BOOL finished) {
[weakSelf.view layoutIfNeeded];
}];
}
picker view, If you have added constraint To TopLayout for yPosition remove it and add constraint to bottom layout instead.
That will solve the problem. here is my code and its working:
self.timePickerHeightConstraint.constant = pickerIsClosed ? 216 :
0;
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutSubviews];
} completion:^(BOOL finished){
}];

UIView animateWithDuration not animating in ios8

I have implemented a custom segue class for emulating the push transition without navigation bar. The trick is to take to snapshots, add them to the view, replace the viewController, move the snapshots, and finally remove them. This emules a horizontal movement of the viewController, but actually only two UIImagesView are moved.
The following code implements this.
self.destinationImageView.frame = offsetFrameD;
self.sourceImageView.frame = offsetFrameS;
//ViewController replacement
[self.sourceViewController presentModalViewController:self.destinationViewController animated:NO];
//Overpose the snapShot who will simulate the transition between vies.
[destinationView addSubview: self.sourceImageView];
[destinationView addSubview: self.destinationImageView];
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.destinationImageView.frame = self.finalFrameD;
self.sourceImageView.frame = self.finalFrameS;
}
completion:^(BOOL finished) {
[self.sourceImageView removeFromSuperview];
[self.destinationImageView removeFromSuperview];
}];
This code worked with iOS 7. However, when using iOS 8, it seems like the animation is not performed. The destinationImageView and sourceImageView are directly moved to the finalPosition (WITHOUT ANIMATING) and the completion block is not called, so both UIImageView are not finally removed.
Does anyone knows how the animation should be performed with iOS 8?
You should adjust the auto layout constraints and not the frames position. Have a look at this solution. I hope it helps.
UIView transitionWithView & setting the frame no longer works iOS8
Use the following line of code before the start of the animation:
[UIView setAnimationsEnabled:YES];

Animation Blocks resets to original position after updating text

I'm currently testing my apps for the release of IOS 8. I noticed that after I performed an animation block, the animation resets if I update the text of any label. I ran a simple example with one method shown below. Running this example results in the following:
Clicking myButton the first time- animation runs but resets when the label text is changed.
Clicking myButton the second time - animation runs but does not reset to original position.
It seems like this happens because the label text doesn't change. If I completely remove the line updating the text, this also stops the animation from resetting at the end.
I would like to fix this so that when the method runs, the label text can be updated without resetting the animation.
- (IBAction)move:(id)sender {
[UIView animateWithDuration:0.4 delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.myButton.center = CGPointMake(200, 300);
}completion:^(BOOL finished){
if(finished){
self.myLabel.text=#"moved";
}
}];
}
This problem can be caused by having Auto Layout set on the UIView. Strictly speaking, if you're using Auto Layout, then you shouldn't animate the absolute position of objects -- you should animate their constraints instead.
Changing the label text once your animation is underway triggers a layout refresh, and iOS shuffles everything around to comply with the original view constraints. (I suspect this is a behavioural change from iOS7).
Quick fix: un-check Auto Layout on the View, and this should work as expected.
Try this. Put the desired animation in the finish block also.
- (IBAction)move:(id)sender {
[UIView animateWithDuration:0.4 delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.myButton.center = CGPointMake(200, 300);
}completion:^(BOOL finished){
if(finished){
self.myLabel.text=#"moved";
self.myButton.center = CGPointMake(200, 300);
}
}];
}

UIView animation happens in the wrong direction

For some reason my UIImageView animates to its start position, from its end position. I can’t work out why but have a feeling it’s something to do with using constraints (I use constraints on all UIViews throughout my app).
My animation should animate logoImageView off the top of the screen.
Here is my code:
NSLog(#"%#", NSStringFromCGPoint(self.logoImageView.center));
[self.logoImageView updateConstraintsIfNeeded];
[UIView animateWithDuration:3.0f
animations:^{
[self.logoImageView setCenter:CGPointMake(CGRectGetMidX(self.logoImageView.frame),
CGRectGetMaxY(self.view.frame) + CGRectGetHeight(self.logoImageView.frame))];
[self.logoImageView updateConstraintsIfNeeded];
} completion:^(BOOL finished) {
NSLog(#"%#", NSStringFromCGPoint(self.logoImageView.center));
[self performSegueWithIdentifier:#"Play" sender:nil];
}];
Here is my log of positions:
2014-09-05 18:08:56.673 Cups[2142:89629] {160, 111.5}
2014-09-05 18:09:01.250 Cups[2142:89629] {160, 645}
But the animation plays the other way round. Any ideas?
This probably has something to do with the fact that you're calling -updateLayoutConstraints without actually updating constraints.
A better approach would be to animate the constraints rather than setting the position and frames of your views. A good trick to remember is that you can create outlets in your XIB to your constraints.
Let's assume you have an NSLayoutConstraint called logoImageViewTopConstraint set up as an IBOutlet in your view controller which sets the top of the logoImageView to it's superview's top layout guide. At design time set that constraint's constant to 100 or so (moving it down 100 points from the top of the view). Then with that constraint you could do something like this for your animation:
[self.view layoutIfNeeded];
self.logoImageViewTopConstraint.constant = 0; // moves image view back to the top
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:0.8 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.view layoutIfNeeded]; // interpolates animation from changes to constraints
} completion:^(BOOL finished) {
// done
}];
If you get it working just play with the constants of the constraints until you get the exact effect that you want.
What happens if you do this:
[UIView animateWithDuration:3.0f
animations:^
{
[self.logoImageView setCenter:CGPointMake(CGRectGetMidX(self.logoImageView.frame),
-(CGRectGetHeight(self.logoImageView.frame)/2)];
} completion:^(BOOL finished)
{
[self performSegueWithIdentifier:#"Play" sender:nil];
}];
animate to y center = -(logoHeight/2). This is "off the top of the screen" in iOS coordinates
don't call updateConstraints in animation block
It turns out a CABasicAnimation running on the layer of the UIView was interrupting the UIView animation. Thanks for suggestions

UIView animateWithDuration not getting executed

I am trying to move a UIView from the bottom to the top.
I am using iOS SDK 7.0, the uiviewcontroller's autolayout is on.
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.view bringSubviewToFront: myView];
[self moveFromBottom];
}
- (void) moveFromBottom{
[myView setBackgroundColor:[UIColor redColor]];
CGPoint top = myView.center;
top.y = self.view.frame.size.height - top.y;
[UIView animateWithDuration:5.0f
delay:0.0f
options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionBeginFromCurrentState
animations:^{
myView.center = top;
}
completion:^(BOOL finished){
if (finished) {
NSLog(#"finished");
}
}
];
The completion block gets executed and print finish but the UIView is not moved.
I also tried animate frame instead of center, which does not work neither.
But if I try to animate alpha instead it will work
edit: if I turn off autolayout in the storyboard it will also work.
You cannot explicitly set the frame or center when Autolayout is turned on. My suggestion would be to create an IBOutlet for the y-origin constraint on myView and set the constant property of that in your animation block. That should animate properly.
Where is myView initially? If it is dead center:
top.y = self.view.frame.size.height - top.y;
will be equal to the initial value of top.y. so it will not move. Did you mean to move it flush to the top. If so I think it should be:
top.y = (myView.frame.size.height/2.0f);
Also if you have auto layout enabled, check what constraints you have and make sure its not forcing it to pin in its position. I would disable auto layout to make sure this is not causing your issue. If all else fails, NSLog the value of top.y to make sure its what you intended.

Resources