Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Kian Woo
Kian Woo
3,097 Points

Animate This - Extra Credit - motionBegan event

Hi, I'm trying to do the Animate This - Extra Credit task for the crystalball app. I managed to animate the predictionLabel from the bottom of the screen upwards, but was not able to animate the predictionLabel down to the bottom of the screen during the motionBegan event. I debugged to check that is the code is being run, and it is, but nothing appears to happen on the simulator. When I don't call the makePrediction method in the motionEnded function, the motionBegan code works and the label moves down! (I tapped to get a prediction, then sent a shake gesture to move it down...)

Any ideas?

Here is the code:

- (void) makePrediction {
    NSUInteger index = arc4random_uniform(self.predictionArray.count);
    self.predictionLabel.text = [self.predictionArray objectAtIndex:index];
    [self.imageView startAnimating];

    self.predictionLabel.frame = CGRectMake(20, 488, 280, 42); // move label to bottom of screen
    [UIView animateWithDuration:2.0 animations:^{
        self.predictionLabel.frame = CGRectMake(20, 205,280, 42); // animate it upwards
    }];
}

- (void) motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
    NSLog(@"motionBegan");
    self.predictionLabel.text = @"is anything happening?";
    if ( motion == UIEventSubtypeMotionShake ){
        [UIView animateWithDuration:2.0 animations:^{
         self.predictionLabel.frame = CGRectMake(20, 488,280, 42); // animate it downwards
        }];
    }
}

- (void) motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
 NSLog(@"motionEnded");
if ( motion == UIEventSubtypeMotionShake ){
    [self makePrediction];
}
}

- (void) motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event {
NSLog(@"motion cancelled");
}

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
 NSLog(@"touchesBegan");
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"touchesEnded");
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 1) {
    [self makePrediction];     
} else if ([touch tapCount] ==2 ) {
    self.predictionLabel.text = @"";
}
}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"touchesMoved");
}

2 Answers

Amit Bijlani
STAFF
Amit Bijlani
Treehouse Guest Teacher

The problem is that motionBegan and motionEnded events happen too quickly that the first animation never gets a chance to finish. If you want to see the label go down and then come back up then you can add the following code to the motionEnded method:

- (void) motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
    if ( motion == UIEventSubtypeMotionShake ){
        [UIView animateWithDuration:1.0 animations:^{
            self.predictionLabel.frame = CGRectMake(20, 488,280, 42); // animate it upwards
        } completion:^(BOOL finished) {
            [self makePrediction];
        }];
    }
}
Amit Bijlani
Amit Bijlani
Treehouse Guest Teacher

I will update the Extra Credit so it's not misleading

Kian Woo
Kian Woo
3,097 Points

Thank you! Yes, that's what I was trying to do, and it works now.

I am having a similar challenge, but I took a different, simpler approach by putting all of the animations into the makePrediction method, thus avoiding the timing issues encountered with using the motionBegan and motionEnded methods. To my complete surprise, I got the same result as Kian in his original post. All of the NSLogs display in the correct order, but the first animation just does not work. This is (in my mind) very straightforward coding, but obviously I am missing something.

- (void)makePrediction
{
    /* This first scrolls the old prediction down off the screen, gets a new prediction
       and scrolls the new predictgion down from the top of the screen. */
    NSLog(@"makePrediction method called");
    NSLog(@"makePrediction - middle down to bottom");
    self.predictionLabel.frame = CGRectMake(20, 205, 280, 56); // set label to middle of screen
    [UIView animateWithDuration:5.0 animations:^{
        self.predictionLabel.frame = CGRectMake(20, 488, 280, 56); // animate it downward
    }];
    NSLog(@"makePrediction - get random prediction");
    NSUInteger index = arc4random_uniform(self.predictionArray.count);
    self.predictionLabel.text = [self.predictionArray objectAtIndex:index];
    NSLog(@"makePrediction - top down to middle");
    self.predictionLabel.frame = CGRectMake(20, 20, 280, 56); // set label to top of screen
    [UIView animateWithDuration:5.0 animations:^{
        self.predictionLabel.frame = CGRectMake(20, 205, 280, 56); // animate it down to middle of screen
    }];
}

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
    NSLog(@"motionBegan method called");
    if ( motion == UIEventSubtypeMotionShake ){
    }
}

- (void) motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
    NSLog(@"motionEnded method called");
    if ( motion == UIEventSubtypeMotionShake ){
        [self makePrediction];
    }
}

I am a newbie here, so how can I paste a block of code and get it to appear normally? In the previous reply, I tried to wrap the code in backticks as explained in the Markdown Basics page, but that did not work either.

Amit Bijlani
Amit Bijlani
Treehouse Guest Teacher

As displayed in my answer above you need to use the method UIView animateWithDuration:animations:completion: and put the code to move the label upward in the completion block because it waits for the first animation to finish. In your code both the animation occur so quickly one after the other that you cannot see one complete and the other begin.

For code formatting use three backticks followed by the name of the language like this:

```objective-c
 // your code
```

Many thanks for all your help, Amit; I was finally able get the animations working as intended, and even built in fade-in and fade-out effects using the alpha value.

Susan Huffaker
Susan Huffaker
3,546 Points

Is it possible to see the finished code that works? I've had trouble with this, too. Thanks!