简体   繁体   中英

UIView animation not working in iOS 7

I am working on a sample project in which I have a vertical scrollview and a horizontal scrollview . The vertical scrollview has a number of subviews. In scrollviewDidScroll I am performing some actions. Along with this I now want to animate a subview inside the vertical scrollview when that particular subview is visible on the screen. For this I am doing a certain calculation which is correct. The animation is as follows:

The subview contains multiple custom views. I am trying to animate(reducing and then again increasing alpha value for the view) each of these views in some particular time sequence(so that the animation looks to be in sequence). For this I am posting notification to the views and the animation sequence and logic is perfect according to what I want.

But I am facing the problem that the code is executing when I put the breakpoint, but the animation does not show up. In case if I post the notification after I stop scrolling then the animation happens perfectly fine. But I want is the animation to happen even when I am scrolling and the view is on screen.

I am adding my code snippet as below:

SubView : (Inside my scrollview )

- (void)animateSequenceTemplate {
if (!hasSequenceTemplateAnimated) {
    [self performSelector:@selector(animateSequenceSlides) withObject:nil afterDelay:0];
    hasSequenceTemplateAnimated = YES;
}
else {
    return;
}
}

- (void)animateSequenceSlides {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:imageAsset forKey:@"assetMO"];
[[NSNotificationCenter defaultCenter]postNotificationName:AnimateSequenceSlide object:nil userInfo:userInfo];
}

Subviews inside the above subview:

- (void)animateSlideView:(NSNotification *)notification {

NSDictionary *userInfo = notification.userInfo;
if ([userInfo objectForKey:@"assetMO"] == assetMO) {
    [[NSNotificationCenter defaultCenter]removeObserver:self name:AnimateSequenceSlide object:nil];

    CGFloat duration = 0.035;
    float delay = (self.slideCount * duration);
    CGFloat timeDelay = 0;


    [self performSelector:@selector(animationPhase1) withObject:nil afterDelay:delay];
    timeDelay = delay + duration;
    [self performSelector:@selector(animationPhase2) withObject:nil afterDelay:timeDelay];

    if (self.slideCount == (self.maxSlideCount - 1)) {
        timeDelay += duration * 18; //No animation till 18 frames
    }
    else {
        timeDelay += duration;
    }
    [self performSelector:@selector(animationPhase3) withObject:nil afterDelay:timeDelay];
    timeDelay += duration;
    [self performSelector:@selector(animationPhase4) withObject:nil afterDelay:timeDelay];
}
}

- (void)animationPhase1 {
[UIView animateWithDuration:0.035 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^ {
    [self setAlpha:0.85];
}completion:^(BOOL finished) {
}];
}

There occurs two scenarios inside - (void)animateSequenceTemplate :

  1. I call as [self animateSequenceSlides]; . In this case the animation does not show up.
  2. [self performSelector:@selector(animateSequenceSlides) withObject:nil afterDelay:0.0f]; . In this case the animation shows up but after the scrollview rests.

I am compelled to use the UIView animation using perform selector because if I remove this and use either nested UIView animate blocks / or directly call these methods, then again animation does not show up. Now at lease it shows up after the I rest scrolling.

I would like advice on a solution or any guess on what mistake I might be making.

It possible, that you executing it not on the main queue.

dispatch_async(dispatch_get_main_queue, block()) might help. When working with animation, main queue the only place for executing code, that makes animation happen.

EDIT:

[self performSelector:@selector(animationPhase1) withObject:nil afterDelay:delay];

I'm not sure, where it happens, but I don't think on main thread. Try this:

[self performSelectorOnMainThread:@selector(animationPhase1) 
                       withObject:nil 
                    waitUntilDone:YES];

I'm not sure about delay, that's why I prefer GCD functions and blocks.

Finally, i got the solution to my question and it is working very fine as expected.

Changes Made:

  1. From "animateSequenceTemplate", calling "animateSequenceSlides" method directly
  2. In "animateSlideView" method mentioned above, instead of using perform selector I created NSTimer object with the required delay, repeat set to NO, and adding the timer in the current run loop
  3. Did the same for calling all the four animationPhase methods
  4. Code works fine as accepted

      - (void)animateSequenceTemplate { if (!hasSequenceTemplateAnimated && self.isSequenceSlideCreated) { hasSequenceTemplateAnimated = YES; [self animateSequenceSlides]; } } - (void)animateSlideView:(NSNotification *)notification { NSDictionary *userInfo = notification.userInfo; if ([userInfo objectForKey:@"assetMO"] == assetMO) { [[NSNotificationCenter defaultCenter]removeObserver:self name:AnimateSequenceSlide object:nil]; CGFloat duration = 0.035; float delay = (self.slideCount * duration); CGFloat timeDelay = 0; NSTimer *animate1 = [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:@selector(animationPhase1) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop]addTimer:animate1 forMode:NSRunLoopCommonModes]; timeDelay = delay + duration; NSTimer *animate2 = [NSTimer scheduledTimerWithTimeInterval:timeDelay target:self selector:@selector(animationPhase2) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop]addTimer:animate2 forMode:NSRunLoopCommonModes]; if (self.slideCount == (self.maxSlideCount - 1)) { timeDelay += duration * 18; //No animation till 18 frames } else { timeDelay += duration; } NSTimer *animate3 = [NSTimer scheduledTimerWithTimeInterval:timeDelay target:self selector:@selector(animationPhase3) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop]addTimer:animate3 forMode:NSRunLoopCommonModes]; timeDelay += duration; NSTimer *animate4 = [NSTimer scheduledTimerWithTimeInterval:timeDelay target:self selector:@selector(animationPhase4) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop]addTimer:animate4 forMode:NSRunLoopCommonModes]; } } 

I am not satisfied with the goodness of the code structure. If you think of any other smart way of doing it, please share.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM