iOS draw dotted line from one view's center to another view's center animating second view using CGAffineTransformMakeTranslationg

I've got a bit of a challenging thing I am trying to build.

Basically, I got this scenario here:

I am able to draw the dotted line thanks to this Stackoverflow answer:

Draw dotted (not dashed!) line

The dotted line drawing is done inside:






-(void)drawDottedLineFromStartingPoint:(CGPoint)startPoint ToEndPoint:(CGPoint)endPoint
    UIBezierPath *path = [[UIBezierPath alloc] init];

    [path moveToPoint:startPoint];
    [path addLineToPoint:endPoint];
    path.lineWidth = 4;

    CGFloat dashes[] = {path.lineWidth * 0, path.lineWidth * 2};

    [path setLineDash:dashes count:2 phase:0];
    path.lineCapStyle = kCGLineCapRound;

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(ctx, [ThemeManager mediumTextColor].CGColor);

    [path stroke];

The problem I am facing is that each smaller circles animate in by falling down into place.

The way I am animating the smaller circle is by using something like:

CGAffineTransformMakeTranslation(0, 50);

When I do that, the dotted lines is drawn from the big circle to the final resting position of the smaller circle, the dotted lines doesn't "follow" the smaller circle as it's being animated and falling down.

So what you see is this:

Is there any easy solution to what I am trying to achieve ? I've tried thinking of using NSTimer and calculating the hypotenuse length, divide by a duration, but I didn't get very far :D


I made an app a while ago that did something similar to what you want, so I modified it do what you're trying to do. I have a class called NodeView, that's just a UIView subclass with one property, called line, which is a UIBezierPath (you could subclass UIImageView to do the same thing). I use a timer to move the nodes, and observe the node's center property so I can call drawRect to stroke the node's line. This version moves the nodes one by one. I set the controller's view to a subclass of UIView, and here's the code in that subclass,

#import "RDView.h"
#import "NodeView.h"

@interface RDView ()
@property (weak, nonatomic) IBOutlet UIView *bigView; // this is equivalent to your large image view from which the other image views drop
@property (strong,nonatomic) NSMutableArray *paths;

@implementation RDView

-(void)didMoveToWindow {
    self.bigView.layer.cornerRadius = self.bigView.frame.size.width/2.0;
    self.paths = [NSMutableArray new];
    self.nodes = [NSMutableArray new];
    for (int i = 0; i<5; i++) {
        NodeView *aNode = [NodeView new];
        CGFloat hue = arc4random_uniform(1000)/1000.0;
        aNode.backgroundColor = [UIColor colorWithHue:hue saturation:1 brightness:1 alpha:1.0];
        aNode.frame = CGRectMake(0, 0, 40, 40);
        [self.bigView layoutIfNeeded]; =;
        [self addSubview:aNode];
        [self.nodes addObject:aNode];

        aNode.line = [UIBezierPath bezierPath];
        CGFloat dashes[] = {0, aNode.line.lineWidth * 4};
        [aNode.line setLineDash:dashes count:2 phase:0];
        aNode.line.lineCapStyle = kCGLineCapRound;
        [aNode.line moveToPoint:[self.bigView center]];
    [self bringSubviewToFront:self.bigView];
    for (NodeView *aNode in self.nodes) {
        [aNode addObserver:self forKeyPath:@"center" options:NSKeyValueObservingOptionNew context:nil];

    [self performSelector:@selector(dropNodes) withObject:nil afterDelay:1];

-(void)dropNodes {
    static int i = 0;
    [NSTimer scheduledTimerWithTimeInterval:.005 target:self selector:@selector(dropNode:) userInfo:@{@"nodeIndex":@(i)} repeats:YES];

-(void)dropNode:(NSTimer *) timer {
    NSInteger i = [timer.userInfo[@"nodeIndex"] integerValue];
    NodeView *node = self.nodes[i];
    [node setCenter: CGPointMake( + (i-2)*.25, + 1)]; // spread the nodes out horizontally and move down
    if ( > 400) {
        [timer invalidate];
        if (i < self.nodes.count-1) {
            [self dropNodes];

-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"center"] ) {
        [self setNeedsDisplay];

- (void)drawRect:(CGRect)rect {
    for (NodeView *aNode in self.nodes) {
        [aNode.line stroke];

You can find a link to my project here,

Need Your Help

TaskFactory.FromAsync with BeginGetRequestStream/EndGetRequestStream hangs

c# asynchronous windows-phone-8

I have a method like this, that hangs when declaring responseObject using Task.Factory.FromAsync()

Within cellForRowAtIndexPath getting height of cell when cells are variable height

iphone ios

I create custom cells within my tableview some have images and are tall some are just text. The height of the cells are calculated in heightForRowAtIndexPath, which I beleive is done before