I have a scrollView with paging enabled and a number N of pages, which are UIViews as subviews of the scrollView.
I'm trying to do the following:
User scrolls to page number n. At that point, 7 CALayers which were previously added to page number n (that is, to page [[scrollView subviews] objectAtIndex:n-1].layer subLayers]) fade in, one after the other.
But I can't figure out how to make the CALayers fadeIn sequentially.So far, I've tried the following 3 approaches from my controller's delegate method: (assume I have an array to the layers and that their opacity was set to 0 upon creation)
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
int pageNumber = floor(self.scrollView.contentOffset.x / self.scrollView.frame.size.width);
if(pageNumber == (n-1))
{
int timeOffset = 0;
[CATransaction begin];
for(CALayer *layer in layerArray)
{
CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@"opacity"];
a.duration = 6;
a.beginTime = timeOffset++;
a.fromValue = [NSNumber numberWithFloat:0.];
a.toValue = [NSNumber numberWithFloat:1.];
[layer addAnimation:a forKey:nil];
}
[CATransaction commit];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
int pageNumber = floor(self.scrollView.contentOffset.x / self.scrollView.frame.size.width);
if(pageNumber == (n-1))
{
int timeOffset = 0;
[CATransaction begin];
for(CALayer *layer in layerArray)
{
CABasicAnimation *a = [CABasicAnimation animation];
a.duration = 6;
a.beginTime = timeOffset++;
[layer addAnimation:a forKey:@"opacity"];
[layer setOpacity:1];
}
[CATransaction commit];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
int pageNumber = floor(self.scrollView.contentOffset.x / self.scrollView.frame.size.width);
if(pageNumber == (n-1))
{
int timeOffset = 0;
for(CALayer *layer in layerArray)
{
[CATransaction begin];
CABasicAnimation *a = [CABasicAnimation animation];
a.duration = 6;
a.beginTime = timeOffset++;
[layer addAnimation:a forKey:@"opacity"];
[layer setOpacity:1];
}
for(CALayer *layer in layerArray)
[CATransaction commit];
}
}
But neither seems to work. When the user scrolls to the right page, all layers become visible at once, without much of a fade and definitely not in any sequential order.
Any ideas?
Actually, it turns out that the key is getting the current time in terms of a frame of reference and adding any time offset to that current time. This works also for non-grouped animations.
For instance, something along the lines of this code would cause n layers (assumed to be stored in some array) to sequentially fade in one after the other, each taking .8 secs.:
CGFloat timeOffset = 0;
[CATransaction begin];
for (CALayer *layer in layers) {
CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@"opacity"];
a.fromValue = @(0);
a.toValue = @(1);
a.fillMode = kCAFillModeForwards;
a.beginTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil] + timeOffset;
a.duration = 0.8;
a.removedOnCompletion = NO;
[layer addAnimation:a forKey:nil];
timeOffset += a.duration;
}
[CATransaction commit];
In the above case, the frame of reference is simply the current time when the invocations take place.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With