This question already has an answer here:
How to pause and resume UIView Animation (without Block Animation)?
(1 answer)
Closed 9 years ago.
i have scrollview, which has zoomscale property inside uiview begin animation,it animates well for some duration,but in between these animations i want to pause the animation and resume the animation,please help me out of this
[UIView beginAnimations:#"anim1" context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:fanim];
z = [[arrImage1 objectAtIndex:1] floatValue];
scroll.zoomScale = z;
NSLog(#" %f",scroll.zoomScale);
if (iw != 0 || ih != 0)
{
image1.frame = CGRectMake(0, 0, iw,ih);
}
z = [[arrImage2 objectAtIndex:1] floatValue];
scroll1.zoomScale = z;
z = [[arrImage3 objectAtIndex:1] floatValue];
scroll2.zoomScale = z;
[UIView commitAnimations];
That is possible by using nstimer. Try using nstimer for starting and pausing animation here is a set of code which you can use. Implement your animation within a method and use the nstimer to fire it and pause it:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self startTimer];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self stopTimer];
}
- (void)startTimer {
NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:3.0] interval:3.0 target:self selector:#selector(this is where your animation method name goest) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
self.animationmethodename = timer;
[timer release];
}
- (void)stopTimer {
[self.animationmethodname invalidate];
self.animationmethodtimer = nil;
}
Then replace the animationmethodname with the name of the method you are using to create the animation.
Related
I've set up some code to scroll (paging) the scrollview automatically, after a TimeInterval. Now I want to stop the scrollview animating, after 4 times. Could someone teach me how to do that?
This is my code.
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(onTimer) userInfo:nil repeats:YES];
- (void) onTimer {
// Updates the variable h, adding 320
abc += 320;
//This makes the scrollView scroll to the desired position
[UIView animateWithDuration:1.5f animations:^{
[scrollView setContentOffset:CGPointMake(abc, 0) animated:NO];
}];
}
First add an ivar to an NSTimer
{
NSTimer *timer;
}
timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(onTimer) userInfo:nil repeats:YES];
Then in the onTimer
- (void) onTimer {
//Create a static int
static int repetition = 0;
repetition ++;
if(repetition == 4)
{
repetition = 0;
//Stop the timer
[timer invalidate];
}
// Updates the variable h, adding 320
abc += 320;
//This makes the scrollView scroll to the desired position
[UIView animateWithDuration:1.5f animations:^{
[scrollView setContentOffset:CGPointMake(abc, 0)animated:NO];
}];
}
i currently have a default looping animation which fade in and out once the view appear, when background processing of data are completed it will stop the current animation an load new animation, in terms of new picture.
i can't seen to stop the animation using [self.view.layer removeAllAnimations]; [self.imageViewBottom.layer removeAllAnimations]; [self.imageViewTop.layer removeAllAnimations];
-(void)nextAnimation:(float)previousWidth {
//picture loop
imageViewTop.image = imageViewBottom.image;
imageViewBottom.image = [imageArray objectAtIndex:[imageArray count] - 1];
[imageArray insertObject:imageViewBottom.image atIndex:0];
[imageArray removeLastObject];
imageViewTop.alpha = 1.0;
imageViewBottom.alpha = 0.0;
[UIView animateWithDuration:4.0
animations:^{
imageViewTop.alpha = 0.0;
imageViewBottom.alpha = 1.0;
}
completion:^(BOOL completed){
[self nextAnimation:stringsize.width];
}
];
-(void)foundSetup
{
//[imageViewTop removeFromSuperview];
//[imageViewBottom removeFromSuperview];
//[buttonCaption removeFromSuperview];
[self.view.layer removeAllAnimations];
[self.imageViewBottom.layer removeAllAnimations];
[self.imageViewTop.layer removeAllAnimations];
//[self.imageArray removeAllObjects];
//self.imageArray = foundImageArray;
}
[UIView animateWithDuration:4.0
animations:^{
imageViewTop.alpha = 0.0;
imageViewBottom.alpha = 1.0;
}
completion:^(BOOL completed){
[self nextAnimation:stringsize.width];
}
Here, in your completion block, you will call the next animation method again regardless of the animation being cancelled or not.
Inside your completion block, only call nextAnimation if completed == YES:
completion:^(BOOL completed){
if (completed)
[self nextAnimation:stringsize.width];
}
This, coupled with removing animations from the views that are actually being animated as suggested by Till, should do it for you.
You can go with timer as well create a timer object and call this function through that object once ur background processing gets over invalidate the object [boothTimer1 invalidate] and call again. In one of my application i have done for similar scenario u mentioned. Declare boothTimer1 in .h
NSTimer* boothTimer1; self.boothTimer1 = [NSTimer scheduledTimerWithTimeInterval:duration target:self selector:#selector(ur function) userInfo:nil repeats:NO];
Now u can invalidate the timer when ur background processing is completed.
I have a CCScene. In its right side I need to have a UIScrollView with some menu elements. I did it this way as I have explained in this previous question Cocos2d and UIScrollView
here is the method creating my scene
+(id) scene: (int) wld{
CCScene *scene = [CCScene node];
LevelsMenu *layer = [LevelsMenu node];
layer = [layer init:wld];
[scene addChild: layer];
[layer setScrollView:[LevelMenuControlView alloc]];
[[[CCDirector sharedDirector] openGLView] addSubview:layer.scrollView.view];
return scene;
}
notice that LevelMenuControlView is just an UIViewController implemented this way:
- (void)loadView{
LevelMenuView *scrollView = [[LevelMenuView alloc] initWithFrame:[UIScreen
mainScreen].applicationFrame];
scrollView.contentSize = CGSizeMake(862, 480);
scrollView.delegate = scrollView;
[scrollView setUserInteractionEnabled:TRUE];
[scrollView setScrollEnabled:TRUE];
[scrollView setShowsVerticalScrollIndicator:FALSE];
[scrollView setShowsHorizontalScrollIndicator:FALSE];
self.view = scrollView;
[scrollView release];
}
While LevelMenuView is the UIScrollView containing the menu elements
It works quite fine. Now the problem is that in the left side of the scene I have a sprite animation that, If I do not touch the screen fine but as soon as I drag the scroll view up or down stops or goes at the same speed of my scrolling finger!!!
Any idea?
I have found this link where someone already experienced the same problem and posted a solution which actually works
http://www.cocos2d-iphone.org/forum/topic/11645
It basically consists in adding this code to the scroll view:
// This should go in your interface.
NSTimer *timer;
// Override
- (void)setContentOffset:(CGPoint)contentOffset {
// UIScrollView uses UITrackingRunLoopMode.
// NSLog([[NSRunLoop currentRunLoop] currentMode]);
// If we're dragging, mainLoop is going to freeze.
if (self.dragging && !self.decelerating) {
// Make sure we haven't already created our timer.
if (timer == nil) {
// Schedule a new UITrackingRunLoopModes timer, to fill in for
CCDirector while we drag.
timer = [NSTimer scheduledTimerWithTimeInterval:[[CCDirector sharedDirector] animationInterval] target:self selector:#selector(animateWhileDragging) userInfo:nil repeats:YES];
// This could also be NSRunLoopCommonModes
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopModes];
}
}
// If we're decelerating, mainLoop is going to stutter.
if (self.decelerating && !self.dragging) {
// Make sure we haven't already created our timer.
if (timer == nil) {
// Schedule a new UITrackingRunLoopMode timer, to fill in for CCDirector while we decellerate.
timer = [NSTimer scheduledTimerWithTimeInterval:[[CCDirector sharedDirector] animationInterval] target:self selector:#selector(animateWhileDecellerating) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
}
}
[super setContentOffset:contentOffset];
}
- (void)animateWhileDragging {
// Draw.
[[CCDirector sharedDirector] drawScene];
if (!self.dragging) {
// Don't need this timer anymore.
[timer invalidate];
timer = nil;
}
}
- (void)animateWhileDecellerating {
// Draw.
[[CCDirector sharedDirector] drawScene];
if (!self.decelerating) {
// Don't need this timer anymore.
[timer invalidate];
timer = nil;
}
}
Thanks a lot to these guys
I am trying to auto scroll my text view and reset it to the top once it's arrived at the end.
I use this code:
-(void)scrollTextView
{
CGPoint scrollPoint = stationInfo.contentOffset;
scrollPoint = CGPointMake(scrollPoint.x, scrollPoint.y + 2);
if (scrollPoint.y == originalPoint.y + 100)
{
NSLog(#"Reset it");
scrollPoint = CGPointMake(originalPoint.x, originalPoint.y);
[stationInfo setContentOffset:scrollPoint animated:YES];
[scroller invalidate];
scroller = nil;
scroller = [NSTimer
scheduledTimerWithTimeInterval:0.1
target:self
selector:#selector(scrollTextView)
userInfo:nil
repeats:YES];
}
else
{
[stationInfo setContentOffset:scrollPoint animated:YES];
}
}
As a result, the text view jumps around wildly, but I don't quite know why. Is there maybe a better way of detecting that the text view is at the bottom? Am I setting the the scrollPoint value wrong?
Edit:
ISSUE SOLVED! I stuck to NSTimer - the missing key was calling -display for the layer.
-(void)scrollTextView
{
//incrementing the original point to get movement
originalPoint = CGPointMake(0, originalPoint.y + 2);
//getting the bottom
CGPoint bottom = CGPointMake(0, [stationInfo contentSize].height);
//comparing the two to detect a reset
if (CGPointEqualToPoint(originalPoint,bottom) == YES)
{
NSLog(#"Reset");
//killing the timer
[scroller invalidate];
scroller == nil;
//setting the reset point
CGPoint resetPoint = CGPointMake(0, 0);
//reset original point
originalPoint = CGPointMake(0, 0);
//reset the view.
[stationInfo setContentOffset:resetPoint animated:YES];
//force display
[stationInfo.layer display];
scroller = [NSTimer
scheduledTimerWithTimeInterval:0.1
target:self
selector:#selector(scrollTextView)
userInfo:nil
repeats:YES];
}
else
{
[stationInfo setContentOffset:originalPoint animated:YES];
}
}
You could also use CoreAnimation and animate the bounds property directly. First animate the scrolling, then in the delegate callback that the animation has finished you reset the content offset.
The callback method has to have the signature
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
You could also use the new block-based methods if you are targeting iOS 4.0 and above. Then there are two blocks to be passed: in the first one you specify what to animate and in the second what to do when the animation is over.
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
Your problem than collapses into a single line of code:
[stationInfo animateWithDuration:10.f delay:0.f options:0 animations:^{
[stationInfo setContentOffset:CGPointMake(0, [stationInfo contentSize].height)];
} completion:^(BOOL finished){
if (finished) [stationInfo setContentOffset:CGPointMake(0,0)];
}];
To be honest I am not 100% sure about the precise block syntax but this is how it should work.
I have a application that runs a timer and performs a action 30 times a second. What I want to do is change the size of a UIButton i have so that every time the timer goes around, it changes the UIButton so that it is a little bit smaller. I have played with a bunch of things I have found online and I still cant figure it out.
Any ideas?
So, to move the comment out - is this generally what you're trying to do?
-(void) calledWhenTimerGoesRound
{
NSLog(#"calledWhenTimerGoesRound");
[UIView beginAnimations:nil context:#"MyAnimation"];
CGRect tempFrame = myButton.frame;
tempFrame.size.width = tempFrame.size.width - 5.0f;
tempFrame.size.height = tempFrame.size.height - 5.0f;
myButton.frame = tempFrame;
[UIView commitAnimations];
}
What does your timer code look like? Here's and example of what should work (resize the button smaller every second):
- (void) startMyTimer
{
NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:#selector(calledWhenTimerGoesRound) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
Try something like:
CGRect tempFrame = myButton.frame;
myButton.frame = CGRectInset(tempFrame,5,5);