Swift : Animate CALayer

13,849

Basically you are trying to resize the layer when user is holding down. Here is a function that can be used to resize a given layer:

If you want origin to be pegged to the left, you will need to set the anchor of the layer first:

layer.anchorPoint = CGPointMake(0.0, 1);

func resizeLayer(layer:CALayer, newSize: CGSize) {

    let oldBounds = layer.bounds;
    var newBounds = oldBounds;
    newBounds.size = size;


    //Ensure at the end of animation, you have proper bounds
    layer.bounds = newBounds

    let boundsAnimation = CABasicAnimation(keyPath: "bounds")
    positionAnimation.fromValue = NSValue(CGRect: oldBounds)
    positionAnimation.toValue = NSValue(CGRect: newBounds)
    positionAnimation.duration = 30
} 

In your case, I am not sure where you are resuming the paused layer though. Also observe every time user taps, a new animation gets added in your handleLongPress method! and this will have unwanted effect. Ideally you need to initiate animation only for the first time, and later, just resume the paused animation you started earlier.

//Flag that holds if the animation already started..
var animationStarted = false

func handleLongPress(sender : UILongPressGestureRecognizer){

  //User is holding down on screen
  if(sender.state == .Began){

    if(animationStarted == false){
      let targetBounds =  CalculateTargetBounds() //Implement this to your need
      resizeLayer(layer, targetBounds)
      animationStarted = true
    }else {
      resumeLayer(layer)
    }
  }else {
    pauseLayer(layer)
  }
}
Share:
13,849
OriginalAlchemist
Author by

OriginalAlchemist

Updated on June 04, 2022

Comments

  • OriginalAlchemist
    OriginalAlchemist almost 2 years

    In the code below I am trying to animate a CALayer from the left side of the screen to the right side of the screen as the user is holding down on the screen (longPressGestureRecognizer). When the user lifts their finger, the CALayer pauses.

    var l = CALayer()
    var holdGesture = UILongPressGestureRecognizer()
    let animation = CABasicAnimation(keyPath: "bounds.size.width")
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setUpView()
    }
    
    func setUpView(){
        l.frame = CGRect(x: 0, y: 0, width: 0, height: 10)
        l.backgroundColor = UIColor.redColor().CGColor
    
        self.view.addGestureRecognizer(holdGesture)
        holdGesture.addTarget(self, action:"handleLongPress:")
    }
    
    func handleLongPress(sender : UILongPressGestureRecognizer){
    
        if(sender.state == .Began) { //User is holding down on screen
            print("Long Press Began")
            animation.fromValue = 0
            animation.toValue = self.view.bounds.maxX * 2
            animation.duration = 30
            self.view.layer.addSublayer(l)
            l.addAnimation(animation, forKey: "bounds.size.width")
        }
        else { //User lifted Finger
            print("Long press ended")
            print("l width: \(l.bounds.size.width)")
            pauseLayer(l)
        }
    }
    
    func pauseLayer(layer : CALayer){
        var pausedTime : CFTimeInterval = layer.convertTime(CACurrentMediaTime(), fromLayer: nil)
        layer.speed = 0.0
        layer.timeOffset = pausedTime
    }
    

    I have two issues:

    1. When i print the width of the CALayer after the animation (when user lifts finger) its always 0. I animate the width, and its expanding, thus I do not know why it does not give me the new width of the CALayer.

    2. After the user lifts their finger, and then holds down again, the CALayer disappears. I need it to remain on the screen, and create another CALayer, I do not delete it in any way, so i do not understand why it is as well disappearing. I checked the memory the object still exists.

    UPDATE to issue #2 : I believe to create another CALayer I can't just add the layer again. I must either create a copy or create a UIView that I can add the layer to. I still do not understand why it is disappearing though.