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.
Related
I am animating an UIImageview in horizontal position for this purpose i have used the below code i have used the NSTimer
timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:#selector(onTimer) userInfo:nil repeats:YES];
-(void)onTimer
{
[UIView animateWithDuration:10.0f animations:^{
//Moving_Cloud is an image view
Moving_Cloud.frame = CGRectMake(200.0f, 150.0f, Moving_Cloud.frame.size.width, Moving_Cloud.frame.size.height);
}];
}
now the problem i am facing is i need to get the coordinates of the "Moving_Cloud" after the animate duration
please help me
Thanks in advance.
Abhijit Chaudhari from the comment in my previous post I understand that what you want is not the position "after the animate duration" but instead the position during the animation.
If I still didn't get it right please clarify your question. (Or buy me an new brain)
-(void) animateMe(){
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(onTimer:) userInfo:nil repeats:YES];
[UIView animateWithDuration:10.0f animations:^{
//Moving_Cloud is an image view
Moving_Cloud.frame = CGRectMake(200.0f, 150.0f, Moving_Cloud.frame.size.width, Moving_Cloud.frame.size.height);
}];
}
-(void)onTimer:(id)sender{
NSLog(#"Currently in x=%f", [[ddddd.layer presentationLayer] frame].origin.x);
NSLog(#"Currently in y=%f", [[ddddd.layer presentationLayer] frame].origin.y);
}
[UIView animateWithDuration:10.0f animations:^{
Moving_Cloud.frame = CGRectMake(200.0f, 150.0f, Moving_Cloud.frame.size.width, Moving_Cloud.frame.size.height);
} completion:^(BOOL finished){
CGPoint newPost = Moving_Cloud.frame.origin;
CGFloat xPos = newPost.x;
CGFloat yPos = newPost.y;
// do stuff ?
}];
At the end of your animation the block "completion:" will be trigger.
Normally your image should be in x = 200, y = 150.
Be aware that those coordinates are relative to it superview (the view wrapping Moving_Cloud view).
Note:
By convention I recommend changing "Moving_Cloud" to "movingCloud".
Instance class start in lower cap in objective-C.
Also don't use _ but a capital letter instead.
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.
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'm having difficulty moving an image from left to right.
Now i have a situation when i have an infinite animation but it just replaces the current image to another.
here's my code:
-(void)startAnimationTest
{
image.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"pic_1.png"],
[UIImage imageNamed:#"pic_2.png"],
[UIImage imageNamed:#"pic_3.png"], nil];
[image setAnimationDuration:1];
image.animationDuration = 4;
[image startAnimating];
}
thank you,
Eliza
Try adding the images to a scroll view and then animating scrollview on the basis of its content offset. See the sample code attached. Make sure of add a nstimer to call the function repeatdly.
- (void) animateScrollView: (id) sender
{
[UIView beginAnimations:nil context:NULL];
CGPoint contentOffset = scrollView.contentOffset;
contentOffset.x +=3;
[scrollView setContentOffset:contentOffset animated:NO];
[UIView commitAnimations];
if (scrollView.contentOffset.x == (scrollView.bounds.size.width * 5)) {
scrollView.contentOffset = CGPointMake(0, scrollView.bounds.origin.y);
}
}
set timer as follows:
[NSTimer scheduledTimerWithTimeInterval: .03
target: self
selector: #selector(animateScrollView:)
userInfo: nil
repeats: YES];
thats it. Hope it helps.
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.