I am doing an animation on a UIView and having it repeat, which is working well like so:
[UIView animateWithDuration:6.0f delay:0.0f options:UIViewAnimationOptionRepeat | UIViewAnimationOptionCurveEaseIn animations:^{
self.imgTopCloud.frame = CGRectMake(-self.imgTopCloud.frame.size.width, self.imgTopCloud.frame.origin.y, self.imgTopCloud.frame.size.width, self.imgTopCloud.frame.size.height);
}completion:nil];
This animates it outside of the view's bounds. Now, when it does that, I want the imgTopCloud's frame to start right at the very end of the view like this:
//Now we start at the very right
self.imgTopCloud.frame = CGRectMake(self.view.frame.size.width, self.imgTopCloud.frame.origin.y, self.imgTopCloud.frame.size.width, self.imgTopCloud.frame.size.height);
The issue is, when the animation starts to repeat, it brings it back to imgTopCloud's original starting frame, not the new one I want. I tried putting the new frame in the completion block of the animateWithDuration message, but no dice.
Any ideas?
Don't repeat that animation. Instead, in the completion block of that animation, you need to do two things.
1) set the frame to the very right
2) start a repeating animation that moves the view to the left
Related
I have four UIViews, positions on the four sides of my full view, e.g.
View 3
View 4 View 2
View 1
(Note that the bottom view is offset a little bit)
They are all 44x44 pixels and look exactly the same.
I have the views move counter clockwise to the next view's location (i.e. View 1 moves to View 2, View 2 moves to View 3, etc.), and View 4 moves to View 1, but not offset. This part works normally, the code is as follows:
[UIView animateWithDuration:0.5 animations:^{
[view1 setFrame:view2.frame];
[view2 setFrame:view3.frame];
[view3 setFrame:view4.frame];
[view4 setFrame:centerFrame];
} completion:^(BOOL finished) {
[self reloadData];
}];
centerFrame is view1's frame not offset.
In the method reloadData, the frames are move back to their original positions, and, because they all look the same, the only thing that users should see is the movement of the bottom view back to its offset position (although it is really changing from view4 to view1). This change looks a little bit sudden, and I wanted to animate it, but I don't want the views to move back, just cross dissolve, so that only the bottom view looks like it changed. I've tried:
[UIView transitionWithView:self.view duration:1.0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
// Reset frames
} completion:nil];
and
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
// Reset frames
} completion:nil];
but both move the views. So my question,
How do I animate a UIView frame change with a cross dissolve animation instead of moving between the points?
Thanks in advance!
You can animated alpha = 0, update the frames in the completion block and then animated alpha = 1. Make the duration of each animation block 1/2 the usual so together they'll take the same time as the rotation event.
If you want to do a simultaneous dissolve then duplicate all the views, set their alpha = 0, update their frames and then animate the alpha of both groups:
old views'.alpha = 0new views'.alpha = 1
a third solution - group all the views in a subview, copy the whole hierarchy and then animate the transition between them using options:UIViewAnimationOptionTransitionCrossDissolve
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);
}
}];
}
I am trying to move a UIView around the screen by incrementing the UIView's x property in an animation block. I want the element to move continuously so I cannot just specify an ending x and up the duration.
This code works but it is very choppy. Looks great in the simulator but choppy on the device.
-(void)moveGreyDocumentRight:(UIImageView*)greyFolderView
{
[UIView animateWithDuration:0.05 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
NSInteger newX = greyFolderView.frame.origin.x + 5.0;
greyFolderView.frame = CGRectMake(newX, greyFolderView.frame.origin.y, greyFolderView.frame.size.width, greyFolderView.frame.size.height);
}
} completion:^(BOOL finished) {
[self moveGreyDocumentRight:greyFolderView];
}];
}
You're fighting the view animation here. Each one of your animations includes a UIViewAnimationOptionCurveEaseInOut timing curve. That means that every 0.05 seconds you try to ramp up your speed then slow down your speed then change to somewhere else.
The first and simplest solution is likely to change to a linear timing by passing the option UIViewAnimationOptionCurveLinear.
That said, making a new animation every 5ms really fights the point of Core Animation, complicating the code and hurting performance. Send the frame it to the place you currently want it to go. Whenever you want it to go somewhere else (even if it's still animating), send it to the new place passing the option UIViewAnimationOptionBeginFromCurrentState. It will automatically adjust to the new target. If you want it to repeat the animation or bounce back and forth, use the repeating options (UIViewAnimationOptionRepeat and UIViewAnimationOptionAutoreverse).
I am trying to animate a transform of a UIButton with CGAffineTransformRotate, and while it is performing the animation properly, it shifts the button about 15 pixels down and to the left before doing it. Here's the code performing the animated transformation:
[UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionTransitionNone
animations:^{
self.addCloseButton.transform = CGAffineTransformRotate(self.addCloseButton.transform, degreesToRadians(45));
}
completion:nil];
When I reverse the transformation it does the same thing except it shifts it back to its original position before animating (15 pixels up and 15 pixels to the right), and I do that with this code:
[UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionTransitionNone
animations:^{
self.addCloseButton.transform = CGAffineTransformIdentity;
}
completion:nil];
Why would this shift occur? The button was created using interface builder, and the shift happens immediately even if I set the animation duration higher or add a delay.
I figured it out: turns out having "Use Autolayout" selected on my xib (which adds a bunch of auto constraints) messes things up when trying to use transforms. Turning it off fixed my problem.
It is posible to fix this while still using auto layout and storyboards. See my answer on this question: https://stackoverflow.com/a/19582959
I am trying to animate the alpha value of a MapKit overlay view (specifically an MKCircleView) in iOS 5 using the following code:
-(void) animateCircle:(MKCircle*)circle onMap:(MKMapView*) mapView
{
MKCircleView * circleView = (MKCircleView*) [mapView viewForOverlay:circle];
UIViewAnimationOptions options = UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionTransitionNone;
[UIView animateWithDuration:5.0
delay:0.0
options:options
animations:^(void) { circleView.alpha = 0.9; }
completion:^(BOOL finished) {}
];
}
The alpha value of the overlay is changing as I want, but it is jumping there instantaneously rather than animating over the specified duration.
Can anyone suggest what might be wrong? Perhaps animation on overlay views os more complex with blocks than I had thought.
Core Animation has interesting behavior when concurrent animations effect the same view... If you try to animate a view before the view's last animation finished, it will assume you intended the subsequent animation to start from the desired end-state of the initial one. This can result in jumps of frames as well as jumps of alpha values.
In your case, this view is likely being animated by something else. Try locating and removing the other animation / or'ing in UIViewAnimationOptionBeginFromCurrentState to its options.