简体   繁体   中英

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:

在此输入图像描述

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

在此输入图像描述

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.

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

Found the answer thanks to @iosengineer on Twitter. When setting a position on the CALayer, you do not want to update the frame of the layer, but you want to update the bounds .

Smooth animation FTW

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