iosswiftanimationcalayeruilongpressgesturerecogni

Swift : Animate CALayer


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.


Solution

  • 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)
      }
    }