Search code examples
iosswiftcore-animation

Update the rotation of a CALayer


I am trying to update the current rotation (and sometimes the position) of a CALayer.

What I am trying to in a couple of simple steps:

  1. Store a couple of CALayers in an array, so I can reuse them
  2. Set the anchor point of all CALayers to 0,0.
  3. Draw CALayer objects where the object starts at a position on a circle
  4. The layers are rotated by the same angle as the circle at that position
  5. Update the position and rotation of the CALayer to match new values

Here is a piece of code I have:

lineWidth is the width of a line
self.items is an array containing the CALayer objects

func updateLines() {

    var space = 2 * M_PI * Double(circleRadius);
    var spaceAvailable = space / (lineWidth)

    var visibleItems = [Int]();

    var startIndex = items.count - Int(spaceAvailable);
    if (startIndex < 0) {
        startIndex = 0;
    }

    for (var i = startIndex; i < self.items.count; i++) {
        visibleItems.append(self.items[i]);
    }

    var circleCenter = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));

    /* Each line should move up and rotate accordin to this value */
    var anglePerLine: CGFloat = (360 / CGFloat(visibleItems.count)).toRadians()

    /* Starting position, 270 degrees is on top */
    var startAngle: CGFloat = CGFloat(270).toRadians();

    /* Lines default rotation, we rotate it to get the right side up */
    var lineAngle: CGFloat = CGFloat(180).toRadians();

    for (var itemIndex = 0; itemIndex < visibleItems.count; itemIndex++) {
        var itemLayer = self.itemLayers[itemIndex];
        itemLayer.opacity = 1 - ((0.9 / visibleItems.count) * itemIndex);

        /* Calculate start position of layer */
        var x = CGFloat(circleRadius) * cos(startAngle) + CGFloat(circleCenter.x);
        var y = CGFloat(circleRadius) * sin(startAngle) + CGFloat(circleCenter.y);
        var height = CGFloat((arc4random() % 80) + 10);

        /* Set position and frame of layer */
        itemLayer.frame = CGRectMake(CGFloat(x), CGFloat(y), CGFloat(lineWidth), height);
        itemLayer.position = CGPointMake(CGFloat(x), CGFloat(y));

        var currentRotation = CGFloat((itemLayer.valueForKeyPath("transform.rotation.z") as NSNumber).floatValue);
        var newRotation = lineAngle - currentRotation;

        var rotationTransform = CATransform3DRotate(itemLayer.transform, CGFloat(newRotation), 0, 0, 1);
        itemLayer.transform = rotationTransform;

        lineAngle += anglePerLine;
        startAngle += anglePerLine;
    }
}

The result of the first run is exactly as I want it to be:

enter image description here

The second run through this code just doesn't update the CALayers correctly and it starts to look like this:

enter image description here

I think it has to do with my code to update the location and transform properties of the CALayer, but whatever I do, it always results in the last picture.


Solution

  • Answered via Twitter: setting frames and transform is mutually exclusive. Happy to help. Finding my login credentials for SO is harder. :D