I have a 8 imagaviews that I have added to my view with size (0,0). Now what I want to do is to pull op each imageView after each other with a UIViewanimation. I want to do 2 animations. First the size should go to from (0,0) --> (105,85) and after that is finished the imageview size should go from (105,85) --> (93,75)
Now I have a method where I first place all my imageViews on the correct place.All the images have size (0,0) At the end I call the method startAnimating
-(void)startAnimating{
[self animageButton:[arrButtons objectAtIndex:0]];
}
Then the first view animation ( from (0,0) --> (105,85) )
-(void)animageButton:(UIImageView *)imgButton{
loopIndex++;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.0];
[UIView setAnimationDelegate:self];
CGRect btnFrame = imgButton.frame;
btnFrame.size.width = 105;
btnFrame.size.height = 85;
[UIView transitionWithView:self.view
duration:0.5f
options:UIViewAnimationOptionCurveEaseIn
animations:^{
imgButton.frame = btnFrame;
}
completion:nil];
[UIView commitAnimations];
[self animageButton2:imgButton];
}
this calls the second method (from (105,85) --> (93,75))
-(void)animageButton2:(UIImageView *)imgButton{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.0];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector: #selector(animationDidStop:finished:context:)];
CGRect btnFrame2 = imgButton.frame;
btnFrame2.size.width = 93;
btnFrame2.size.height = 75;
[UIView transitionWithView:self.view
duration:0.5f
options:UIViewAnimationOptionCurveEaseIn
animations:^{
imgButton.frame = btnFrame2;
}
completion:nil];
[UIView commitAnimations];
}
Now at this point the first imageView should be animated. Now when the animation has finished. I to this.
-(void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
//do smth
if(loopIndex <= 7){
NSLog(#"called");
UIImageView *imgObj = [arrButtons objectAtIndex:loopIndex];
[self animageButton:imgObj];
}else{
NSLog(#"done");
return;
}
}
What it is doing at the moment it is animating all the images at the same time. But I want that the next imageview starts animating when the previous has done.
Can anyone help me with this ?
-(void)startAnimating
{
NSTimeInterval delay = 0.0;
for(UIImageView *imageView in arrButtons)
{
[self performSelector:#selector(animageButton:) withObject:imageView afterDelay:delay];
delay +=1.0;
}
}
-(void)animageButton:(UIImageView *)imgButton{
CGRect btnFrame = imgButton.frame;
btnFrame.size.width = 105;
btnFrame.size.height = 85;
[UIView animateWithDuration:0.5f animations:^{
imgButton.frame = btnFrame;
} completion:^(BOOL finished) {
[self animageButton2:imgButton];
}];
}
-(void)animageButton2:(UIImageView *)imgButton
{
CGRect btnFrame2 = imgButton.frame;
btnFrame2.size.width = 93;
btnFrame2.size.height = 75;
[UIView animateWithDuration:0.5f animations:^{
imgButton.frame = btnFrame2;
} completion:^(BOOL finished) {
}];
}
I have not tested the code. Let me know if there are any issues. Thanks.
Related
I'm trying to show an intermittent label with two changing strings (like a banner) in an infinite loop.
The first label should fade in. After that it should fade out and let a second label do the same. Then repeat the sequence infinitely or a long time.
The label is inside a subclass of a UITableView.
I tried this so far:
- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
// Inside a cell an at its own section of the tableview
cell.label1.alpha = 1;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationRepeatCount:INFINITY];
[cell.label1 setAlpha:0];
[UIView setAnimationRepeatAutoreverses:YES];
[UIView commitAnimations];
cell.label2.alpha = 1;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationRepeatCount:INFINITY];
[cell.label1 setAlpha:0];
[UIView setAnimationRepeatAutoreverses:YES];
[UIView commitAnimations];
...
}
This code works fine but the effect is not clear because the fade in label1 is crossing fade out label2 and it is weird.
So, how can I make a break between the two animations, to see the fading labels clearly?
Thanks #Paulw11 for your answer, now it works fine, here is my code with the changes:
cell.label2.alpha = 0;
cell.label1.alpha = 1;
[UIView animateKeyframesWithDuration:15 delay:0.0 options:0 animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.25 animations:^{
cell.label1.alpha = 0;
cell.label2.alpha = 0;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:0.25 relativeDuration:0.25 animations:^{
cell.label1.alpha = 0;
cell.label2.alpha = 1;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:0.50 relativeDuration:0.25 animations:^{
cell.label1.alpha = 0;
cell.label2.alpha = 0;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:0.75 relativeDuration:0.25 animations:^{
cell.label1.alpha = 1;
cell.label2.alpha = 0;
[self.view layoutIfNeeded];
}];
[UIView setAnimationRepeatCount: 200];
} completion:nil];
This is a continuation of this question
CGRectMake : How To Calculate X and Y For UIPickerView Animation?
answered by https://stackoverflow.com/users/2315974/danypata
I have a picker view that I want to animate on and off screen on a button press and using the code in the previous question/answer I have got it to animate on screen the first time the button is pressed.
the second tome the button is pressed it just disappears and then the third time it is pressed it animates to the wrong place...please help
the code
if (self.pickerSort.hidden == NO) {
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.pickerSort.frame = CGRectMake(0,self.view.frame.size.height
+ self.pickerSort.frame.size.height,-self.pickerSort.frame.size.width,-self.pickerSort.frame.size.height);
}
completion:^(BOOL finished) {
}];
self.pickerSort.hidden = YES;
// [self performSelector:#selector(hidePicker) withObject:nil afterDelay:1];
} else if (self.pickerSort.hidden == YES) {
self.pickerSort.hidden = NO;
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.pickerSort.frame = CGRectMake(0 ,
self.view.frame.size.height
- self.pickerSort.frame.size.height,
self.pickerSort.frame.size.width,
self.pickerSort.frame.size.height);
}
completion:^(BOOL finished) {
}];
[self.view bringSubviewToFront:self.pickerSort];
Behavior in images - button press animates onto screen beautifully
Second Press it disappears with no animation
Third Press it animates to here
Any help would be great...functionality I am looking for is how to put the picker view back on an animation so the 3rd press is the same as the first
Please try to use the below code.
self.pickerSort.hidden = NO;
NSTimeInterval duration = 0.5;
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{
CGRect pickerFrame = self.pickerSort.frame;
// currently picker is off the screen, show it.
if (pickerFrame.origin.y == self.view.frame.size.height) {
// set frame to show picker
pickerFrame.origin.y = self.view.frame.size.height - self.pickerSort.frame.size.height;
} else {
// set frame to hide picker
pickerFrame.origin.y = self.view.frame.size.height;
}
self.pickerSort.frame = pickerFrame;
}
completion:^(BOOL finished) {
self.pickerSort.hidden = YES;
}];
After playing around with this and learning the ins and outs of frames and CGRects, I achieved this by using the following code
if (pickerSort.hidden == YES) {
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
pickerSort.hidden = NO;
visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
[self.tableStations addSubview:visualEffectView];
pickerSort.frame = CGRectMake(0,0,originalPickerFrame.size.width,originalPickerFrame.size.height);
visualEffectView.frame = CGRectMake(0,0,originalPickerFrame.size.width,originalPickerFrame.size.height - 64);
}
completion:^(BOOL finished) {
self.navigationController.navigationItem.leftBarButtonItem.enabled = NO;
}];
}
else
{
visualEffectView.hidden = YES;
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
pickerSort.frame = CGRectMake(0,-originalPickerFrame.size.height,0,0);
}
completion:^(BOOL finished) {
self.navigationController.navigationItem.leftBarButtonItem.enabled = YES;
pickerSort.hidden = YES;
}];
}
I set the original frame size in viewDidLoad like so
pickerSort = [[UIPickerView alloc]initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height)];
originalPickerFrame = pickerSort.frame;
pickerSort.frame = CGRectMake(0,-originalPickerFrame.size.height,0, 0);
Hope this can help somebody in the future
I'm trying to flip animate a view into another view, which corresponds of a small section of the screen. Both views have the same dimensions and center.
I keep getting as a result the animation of the full screen. From the code below, can somebody please let me know what the heck i'm doing wrong?
Thank you,
-j
+ (void) flipView:(UIView*)viewA toView:(UIView*)viewB wait:(Boolean)wait
{
// get parent view
UIView *parent = [viewA superview];
CGRect r = viewA.frame;
// create container view with the same dimensions as ViewA
UIView *containerView = [[UIView alloc] initWithFrame:viewA.bounds];
containerView.center = viewA.center;
// attache both views to intermidiate view
[containerView addSubview:viewA];
[containerView addSubview:viewB];
[viewA removeFromSuperview];
[parent addSubview:containerView];
viewB.alpha = 0;
viewA.alpha = 1;
// Perform the annimation
__block BOOL done = NO;
[UIView transitionWithView:viewA
duration:2.0
options: (UIViewAnimationOptionTransitionFlipFromTop)
animations:^{
viewA.alpha = 0;
viewB.alpha = 1; }
completion:^(BOOL finished) {
done = YES;
// detach all views
[viewA removeFromSuperview];
[viewB removeFromSuperview];
[containerView removeFromSuperview];
}
];
if(wait) {
while (done == NO)
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
}
First get rid of the old animation code (or at least commit it), it should look like this:
+ (void) flipView:(UIView*)viewA toView:(UIView*)viewB wait:(BOOL)wait
{
viewB.alpha = 0;
viewA.alpha = 1;
__block BOOL done = NO;
[UIView transitionWithView:viewA
duration:2.0
options: (UIViewAnimationOptionTransitionFlipFromTop)
animations:^{
viewA.alpha = 0;
viewB.alpha = 1; }
completion:^(BOOL finished) {
done = YES;
}
];
if(wait) {
while (!done)
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
}
Second, the superview of the subview that you want to transition is actually going to get the transition. So this means that you'll have to add viewA and viewB to a subview, add this subview to another view and then do the animation.
Here is a solution without any hacks with runloop. Just use the first message to run a transition to another view, and the second message to return to original state:
- (void) forwardTransitionFromView: (UIView *) viewA toView: (UIView *) viewB
{
NSAssert(viewA.superview, #"The 'from' view should be added to a view hierarchy before transition");
NSAssert(!viewB.superview, #"The 'to' view should NOT be added to a view hierarchy before transition");
CGSize viewASize = viewA.bounds.size;
viewB.frame = CGRectMake(0.0, 0.0, viewASize.width, viewASize.height);
[UIView transitionWithView:viewA
duration:1.0
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[viewA addSubview:viewB];
}
completion:NULL];
}
- (void) backwardTransitionFromView: (UIView *) viewB toView: (UIView *) viewA
{
NSAssert([viewB.superview isEqual:viewA], #"The 'from' view should be a subview of 'to' view");
[UIView transitionWithView:viewA
duration:1.0
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
[viewB removeFromSuperview];
}
completion:NULL];
}
Why dont you flip both views in same direction?
-(void) FlipView:(bool) fromRight {
if(fromRight) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
[UIView setAnimationDelegate:self];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:view1 cache:YES];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:view2 cache:YES];
[UIView commitAnimations];
}
else {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
[UIView setAnimationDelegate:self];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:view1 cache:YES];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:view2 cache:YES];
[UIView commitAnimations];
}
}
and call the method like below:
[view1 setHidden:NO];
[self FlipView:YES];
[view2 setHidden:YES];
to reverse the animation:
[view2 setHidden:NO];
[self FlipView:NO];
[view1 setHidden:YES];
I created a UIView Animation, my array contains 10 images. I want to move one place to another place when button is pressed. Below code is working but problem is all 10 images is moving.
-(IBAction)moveImageAtIndex:(int)index {
UIButton *buttonCelebrate = [redAppleArray objectAtIndex:j];
UIButton *buttonRefer = [reffButtonArray objectAtIndex:j];
currentView = buttonCelebrate;
CGRect frame = currentView.frame;
CGRect frame1 = buttonRefer.frame;
frame.origin.x = frame1.origin.x;
frame.origin.y = frame1.origin.y;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 2.0];
[UIView setAnimationDelegate:self];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
currentView.frame = frame;
[UIView animateWithDuration:2.0 animations:^
{
[currentView setTransform:CGAffineTransformIdentity];
}completion:^(BOOL finished) {
if (finished) {
if(index != [redAppleArray count] - 1) {
[self moveImageAtIndex:index+1];
}
}
}];
[UIView commitAnimations];
}
Expected Output is: I want to move one by one instead of all.
screenshot
You have to wait until the current animation has finished, then you can start the next animation. A simple solution is to use recursion:
-(void)moveImageAtIndex:(int)index {
[UIView animateWithDuration:2.0 animations:^{
//Do animation
}completion:^(BOOL finished) {
if (finished) {
if(index != [redAppleArray count] - 1) {
[self moveImageAtIndex:index + 1];
}
}
}];
}
Remove the code from loop and keep in the method which is called by button then by pressing the button your images in array will be moved one by one according to user clicks.
declare i as int in the .h file and make i value as 0 in viewDidLoad and Don't forget to increment the i value in the end
use below code
-(void)viewDidLoad {
i=0;
[super viewDidLoad];
}
-(IBAction)methodName:(id)sender {
UIButton *buttonCelebrate = [redAppleArray objectAtIndex:index];
currentView = buttonCelebrate;
CGRect frame = currentView.frame;
CGRect frame1 = reffButton.frame;
frame.origin.x = frame1.origin.x;
frame.origin.y = frame1.origin.y;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 2.0];
[UIView setAnimationDelegate:self];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
currentView.frame = frame;
[UIView animateWithDuration:2.0 animations:^
{
[currentView setTransform:CGAffineTransformIdentity];
}completion:^(BOOL finished) {
if (finished) {
}
}];
[UIView commitAnimations];
i++;
}
as per the Eric use below code
You have to wait until the current animation has finished, then you can start the next animation. A simple solution is to use recursion:
-(void)moveImageAtIndex:(int)index {
[UIView animateWithDuration:2.0 animations:^{
UIButton *buttonCelebrate = [redAppleArray objectAtIndex:i];
currentView = buttonCelebrate;
CGRect frame = currentView.frame;
CGRect frame1 = reffButton.frame;
frame.origin.x = frame1.origin.x;
frame.origin.y = frame1.origin.y;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 2.0];
[UIView setAnimationDelegate:self];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
currentView.frame = frame;
[UIView animateWithDuration:2.0 animations:^
{
[currentView setTransform:CGAffineTransformIdentity];
}completion:^(BOOL finished) {
if (finished) {
if(index != [redAppleArray count] - 1) {
[self moveImageAtIndex:index + 1];
}
}
}];
[UIView commitAnimations];
}
The new solution is:
-(void)moveImageStartAtIndex:(int)index withHowMany:(int)howMany{
[UIView animateWithDuration:2.0 animations:^{
//Do animation
}completion:^(BOOL finished) {
if (finished) {
if(howMany > 1) {
[self moveImageStartAtIndex:index + 1 withHowMany:howMany - 1];
}
}
}];
}
I created this animation and I entered through the stop animation
[UIView setAnimationDidStopSelector:#selector (TermineAnimazioneGoPointAssignedWithDelay)] ;
When the animation part of the SetAnimationDidStop is not called ... Can you tell me why and where am I doing wrong ?
This is all the way animation :
-(void)setViewStatusGoPointassigned {
ViewgoPointAssignMessage = [[UIView alloc] initWithFrame:CGRectMake(115, 150, 100, 100) ];
ViewgoPointAssignMessage.backgroundColor = [UIColor colorWithRed:(77/255.0) green:(108/255.0) blue:(143/255.0) alpha:(1)];
[ViewgoPointAssignMessage.layer setCornerRadius:10.0f];
[ViewgoPointAssignMessage.layer setMasksToBounds:YES];
[UIView animateWithDuration:0.2 animations:^{
ViewgoPointAssignMessage.transform = CGAffineTransformMakeScale(1.05, 1.05);
ViewgoPointAssignMessage.alpha = 0.8; }
completion:^(BOOL finished){
[UIView animateWithDuration:2/15.0 animations:^{
ViewgoPointAssignMessage.transform = CGAffineTransformMakeScale(0.9, 0.9);
ViewgoPointAssignMessage.alpha = 0.9; }
completion:^(BOOL finished) {
[UIView animateWithDuration:1/7.5 animations:^{
ViewgoPointAssignMessage.transform = CGAffineTransformIdentity;
ViewgoPointAssignMessage.alpha = 1.0; } ];
} ];
} ];
[self.view addSubview:ViewgoPointAssignMessage];
[UIView setAnimationDidStopSelector:#selector(TermineAnimazioneGoPointAssignedWithDelay)];
}
-(void)TermineAnimazioneGoPointAssignedWithDelay {
[self performSelector:#selector(EliminazioneViewAfterDelay) withObject:self afterDelay:0.01];
}
-(void)EliminazioneViewAfterDelay {
CGRect endREct;
endREct = CGRectMake(350 , 0 , 330, 90);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.005];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(EliminaAnimazione)];
ViewgoPointAssignMessage.frame = endREct;
[UIView commitAnimations];
}
- (void)EliminaAnimazione {
[ViewgoPointAssignMessage removeFromSuperview];
}
First of all, to answer your question.
You may try
[UIView animateWithDuration:(NSTimeInterval)duration animations:^(void)animations completion:^(BOOL finished)completion]
and call [self TermineAnimazioneGoPointAssignedWithDelay] in the completion.
Secondly, [UIView setAnimationDidStopSelector:#selector(TermineAnimazioneGoPointAssignedWithDelay)] doesn't work because according to the reference, setAnimationDidStopSelector must be called between calls to the beginAnimations:context: and commitAnimations methods. Since your code doesn't comply to this rule, the function does not work either.
Hopefully it explains! Good Luck!