Combine a CALayer Position Animation with a value animation … ???

I came around this problem during a project where we should move a formatted text containing a number like, e.g. „It took x seconds to complete the task“. During the movement x should be incremented to following the timing function of the position animation.

I have to confess I had to think about it twice but shortly I thought CALayer can animation almost anything, so why not a custom variable.

So here is the basic idea.

I created a basic CALayer with our count instance variable which gives us the current count value during the position animation.

The implementation is as simple a telling our CounterLayer that we need an information whenever our count value changes. This is done with

+ (BOOL)needsDisplayForKey:(NSString *)key

method. This forces the layer to call its delegate

– (void)displayLayer:(CALayer *)layer


quite early in its update cycle to give the delegate the chance to update the contents property directly.

As we are only interested in the count’s current value, we grab it from the presentation layer for further use.

You can find the whole project on GitHub.

 [fusion_builder_container hundred_percent=“yes“ overflow=“visible“][fusion_builder_row][fusion_builder_column type=“1_1″ background_position=“left top“ background_color=““ border_size=““ border_color=““ border_style=“solid“ spacing=“yes“ background_image=““ background_repeat=“no-repeat“ padding=““ margin_top=“0px“ margin_bottom=“0px“ class=““ id=““ animation_type=““ animation_speed=“0.3″ animation_direction=“left“ hide_on_mobile=“no“ center_content=“no“ min_height=“none“]

@interface CounterLayer : CALayer
@property (nonatomic, assign) NSInteger count;

@interface MovingCounterView : UIView
@property (nonatomic, strong) CounterLayer   *counterLayer;

@implementation MovingCounterView

#pragma mark - CALayer Delegate

- (id)init
    self = [super init];
    if (self) {
        [self.layer addSublayer:self.counterLayer];
    return self;

- (CounterLayer *)counterLayer
    if (nil == _counterLayer) {
        CGRect frame = CGRectMake(0.f, 0.f, 25.f, 300.f);
        _counterLayer                = [CounterLayer layer];
        _counterLayer.contentsScale  = [[UIScreen mainScreen] scale];
        _counterLayer.frame          = frame;
        // here we make sure we got informed
        // when our layer animates
        _counterLayer.delegate       = self;
        _counterLayer.contents       = (id)[UIImage imageNamed:@"SomeImage"].CGImage;
    return _counterLayer;

- (void)startMarkerAnimationToYPosition:(CGFloat)yPos duration:(CFTimeInterval)duration
    CAMediaTimingFunction *timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

    // position animation
    CABasicAnimation *posAnim = [CABasicAnimation animationWithKeyPath:@"position"];;
    posAnim.timingFunction = timingFunction;
    // configure the posAnim as usual
    [self.counterLayer addAnimation:posAnim forKey:@"position"];
    // moving count animation
    CABasicAnimation *countAnim = [CABasicAnimation animationWithKeyPath:@"count"];
    countAnim.fromValue      = @(0);
    countAnim.toValue        = @(200);
    countAnim.duration       = duration;
    countAnim.timingFunction = timingFunction;
    self.counterLayer.count  = 200;
    [self.counterLayer addAnimation:countAnim forKey:@"count"];

#pragma mark - CALayer Delegate

- (void)displayLayer:(CALayer *)layer
    if ([layer isKindOfClass:[CounterLayer class]]) {
        NSInteger currentCount = [[layer.presentationLayer valueForKey:@"count"] integerValue];
        // update a text with this value


@implementation CounterLayer

@dynamic count;

+ (BOOL)needsDisplayForKey:(NSString *)key
    return [key isEqualToString:COUNT_KEY] || [super needsDisplayForKey:key];


And here is the youtube video.

For privacy reasons YouTube needs your permission to be loaded. For more details, please see our Impressum.