Im using a UIView animations to move up/down a view (Using Autolayout) .
Animation works on simulator but it doesn't on actual device. What could be the problem? Code to do the animation is here
[self layoutIfNeeded];
[UIView animateWithDuration:.5 animations:^{
self.animationConstraint.constant = -190;
[self bringSubviewToFront:self.containerView];
[self.containerView layoutIfNeeded];
}];
I have checked the memory usage, but it doesn't cross more than 2% at the time of doing the animations.
Is the simulator device the same like the actual device in regard to iOS and display size?
Related
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()
}
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];
Here is the view that I created using Storyboard:
Clouds, avatar image button, and other text buttons, etc. are its subviews. In its viewDidAppear method, I added several animation methods which cause the clouds to "float" horizontally, for example:
[UIView animateWithDuration:4.0f
delay:0.0f
options:(UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat | UIViewAnimationOptionAllowUserInteraction)
animations:^{
_cloud1.frame = its new frame so that it looks to float horizontally;
}
completion:nil];
Now I have another subview which I created using a XIB file. It's basically a custom-sized subview which will appear when the avatar image button is tapped (we can think of it as "editing profile screen" in social apps). I added it with this animation block (please note that it justs appear on top of the purple circle, which is actually not removed):
_editProfileViewController = [[EditProfileViewController alloc] initWithNibName:nil bundle:nil];
[self addChildViewController:_editProfileViewController];
[_editProfileViewController didMoveToParentViewController:self];
[UIView transitionWithView:self.view duration:0.3 options:(UIViewAnimationOptionTransitionCrossDissolve) animations:^
{
[self.view addSubview:_editProfileViewController.view];
} completion:NULL];
Problem: When I do that, all clouds stop animating (while the transition still works).
Any ideas? Thank you.
After hours banging my head against the wall, it seems that this is an iOS simulator bug. Everything works ok on device.
Note for anyone who faces the same problem:
OS: Mavericks 10.9.4
Xcode: 5.1.1
iOS Simulator target: iOS 7.1
I have a viewcontroller with a view that I am dismissing using a UIView animation to scale it down to 0 before removing it. My code for dismissing it is:
[UIView animateWithDuration:_dismissAnimationDuration
delay:0.0
options:UIViewAnimationOptionCurveEaseIn
animations:^(void) {
_menuContainerView.transform = CGAffineTransformMakeScale(0.0, 0.0);
}
completion:^(BOOL finished){
if ([_delegate respondsToSelector:#selector(popUpMenuDidClose)])
{
[_delegate popUpMenuDidClose];
}
[self.view removeFromSuperview];
[self removeFromParentViewController];
}];
That works perfectly when building from XCode 5 onto devices running both iOS 7 and iOS 8. But, as soon as I build to iOS 8 from XCode 6 (beta 6 and beta 7) the view just cuts away instead of animating. If that wasn't weird enough as soon as I change the target scale to (0.001, 0.001) it animates fine regardless of XCode version. Any ideas as to why I can't animate to an actual (0.0, 0.0) scale with XCode 6?
So after speaking with a developer at Apple the reasoning I got back was that some base frameworks need to work with the inverses of transform matrices quite often, and since there is no inverse for the zero matrix the animation just returns out to avoid crashing. Hopefully this post has helped others who ran into a similar situation.
If acceptable for you, set the scale values to 0.01 like so:
_menuContainerView.transform = CGAffineTransformMakeScale(0.01, 0.01);
Reference
I'm trying to find a reason why animation of UIView transform property looks different in iOS 8 than iOS 6/7.
For a simple example, prior to iOS 8:
myView.transform = CGAffineTransformRotate(CGAffineTransformIdentity, 1.57);
[UIView animateWithDuration:5 animations:^{
myView.transform = CGAffineTransformTranslate(plane.transform, 100, 0);
}];
gives expected result, "myView" is rotated 90 degrees and moves down, but in iOS8 when translation is animated it starts at a point that I couldn't find explanation for (which breaks the animation).
Does anyone know the explanation for it? Thanks in advance!
CGAffineTransformIdentity behaves differently on ios7 and ios8. This has to do with auto-layout and size classes. The solution is to remove constraints that conflict with the animation on ios7.
// solve the constraint-animation problem
if(NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) {
// iOS7 remove constraints that conflict with animation
if (self.centerYAlignment != nil) {
self.view.removeConstraint(self.centerYAlignment) //is an IBOutlet
}
} else {
// iOS8 constraint animations are fine
}
I think the reason is just iOS8 bug, but I use CAAnimation instead, and it works as expected on iOS8.
I had problems with jerky rotation transform in iOS7 as well. Solved this by nesting my rotated view inside a container and centering the rotated view inside.
I'm also experiencing the same issue with scaling. I guess it could be the same with rotation. Could you try this?
myView.transform = CGAffineTransformConcat(myView.transform , CGAffineTransformMakeRotate(1.57));
[UIView animateWithDuration:5 animations:^{
myView.transform = CGAffineTransformTranslate(plane.transform, 100, 0);
}];
Maybe it's also necessary to use CGAffineTransformMakeTranslate and CGAffineTransformConcat that as well, I'm not sure.
The worst part about this is: You would have to do if/else on iOS versions, because this would look weird on iOS 7. I hope this is getting fixed by Apple before or with iOS 8 release.
I agree with Pbk that it has to do with size classes in io8. uiviewcontrollers need to be resized with uitraitcollections depending on the device orientation. Otherwise, you get a uiviewcontroller in portrait mode, while the phone is in landscape mode, when you try to rotate it. So the correct steps are to rotate AND override uitraitcollections
This isn't entirely related, but I was struggling with CGAffineTransformScale not working at all on iOS7 in a fairly complicated animation. It turns out my problem was iOS7 cannot calculate CGAffineTransformScale with CGAffineTransformRotate at the same time. In iOS7, the last animation call you make is the only one that gets animated, so only the rotation was occurring. This bug is fixed in iOS8.
My solution is to simplify my animation for iOS7, only turning on the fancy stuff in iOS8:
//Pre-animation setup:
CGFloat radians = (M_PI/180) * (-15); //Get a human-readable number in degrees
self.badgeImage.alpha = 0; //Start the image as invisible
self.badgeImage.transform = CGAffineTransformScale(self.badgeImage.transform, 1.5, 1.5); //Start the image as scaled bigger than normal
if(NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1) { //See below. We will not be rotating the image in iOS7
self.badgeImage.transform = CGAffineTransformRotate(self.badgeImage.transform, radians); //Rotate the image if iOS8
}
//Animation Pieces:
//Fade in
[UIView animateWithDuration: 0.5
delay:0
options:0
animations:^{
self.badgeImage.alpha = 1.0f; //Return image to opaque
}
completion:NULL];
//Scale with bounce
[UIView animateWithDuration: 1.1
delay:0
usingSpringWithDamping:0.3 //Not as good as Android's bounce interpolator, but I'll take it
initialSpringVelocity:-1.0f //A negative velocity here makes the animation appear more like gravity than spring
options:0
animations:^{
self.badgeImage.transform = CGAffineTransformScale(self.badgeImage.transform, 0.67, 0.67); //Return image to its original size. These arguments are relative to its current scale.
}
completion:NULL];
//Rotation
if(NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1) { //This second animation call negates the first one on iOS7, so remove it.
[UIView animateWithDuration: 0.9
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.badgeImage.transform = CGAffineTransformRotate(self.badgeImage.transform, (radians * -1)); //Rotate the image back to its original orientation if iOS8
}
completion:NULL];
}
Of course, you can still combine multiple effects in iOS7 if you use the confusingly-named CGAffineTransformMakeScale() function. For instance, in the pre-animation setup, you can set both a rotation AND a scale, then set call CGAffineTransformMakeScale(1,1) to reset the image to its original metrics (MakeScale's arguments are specific, not relative - even more confusing!). This isn't always preferable, such as my example above where "bouncing" the animation would also bounce the rotation.