Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding spring to pageCurl CATransition

I have managed (through the help of StackOverflow) to add a partial page curl programatically to my UIPageViewController. This is used a hint to the user that they have completed that page/screen and can proceed.

The code looks like this:

let animation = CATransition()
animation.duration = 0.3
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault)
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = false
animation.endProgress = 0.2
animation.type = "pageCurl"

myPageViewController.view.layer.add(animation, forKey: "MyTransition")

And here's what it looks like (apologies for poor quality - mp4 to gif not so good) enter image description here

What i'd really like to do now is add some spring to that animation, so it looks a little nicer. But i'm finding it really difficult to get any information off Google (may not even be possible?).

This is what i've tried:

// Can't see an animation type on here, maybe keyPath is used as the type?
let x = CASpringAnimation(keyPath: "pageCurl")

// No endProgress either, just trying some random values now
x.fromValue = 0
x.toValue = 1

// No idea - found on Google - can play with the settings later
x.damping = 5
x.duration = x.settlingDuration

// These look familiar from my working animation, so i'll set these!
x.fillMode = kCAFillModeForwards
x.isRemovedOnCompletion = false

myPageViewController.view.layer.add(x, forKey: "MyNewTransition")

... and it does absolutely nothing. Not even a crash. I expect it's because you cant use pageCurl as the keyPath, iOS doesn't know what to do with it, so it's ignored.

Here's a video showing roughly what I want from this...

enter image description here

So does anyone have any idea if it's possible to do this pageCurl animation, but with some spring?

like image 610
TRG Avatar asked Nov 29 '25 15:11

TRG


1 Answers

Edit for new gifs:

class ViewController: UIViewController {

var animated:Bool = false
var counter: Int = 0
var transition = CATransition()

override func viewDidLoad() {
    super.viewDidLoad()

    view.layer.backgroundColor = UIColor.white.cgColor
}

@IBAction func animate(_ sender: Any) {
    animated = false
    counter = 0
    animateCurlPage(start: 0.0, end: 0.35, duration: 0.4)
}

func animateCurlPage(start: Float, end: Float, duration: CFTimeInterval) {


    if (counter == 3) { return }

    UIView.animate(withDuration: duration, animations: {
        if (self.animated) { return }
        self.transition.type = "pageCurl"
        self.transition.subtype = kCATransitionFromBottom
        self.transition.duration = duration
        self.transition.startProgress = start
        self.transition.endProgress = end
        self.transition.delegate = self
        self.transition.fillMode = kCAFillModeForwards
        self.transition.isRemovedOnCompletion = false

        self.view.layer.add(self.transition, forKey: "transition1")
    })

    if animated {
        animateRepeatCurlPage()
    }
}

func animateRepeatCurlPage() {

    UIView.animate(withDuration: 0.15, animations: {
        self.transition.type = "pageCurl"
        self.transition.subtype = kCATransitionFromBottom
        self.transition.duration = 0.15
        self.transition.startProgress = 0.32
        self.transition.endProgress = 0.31
        self.transition.delegate = self
        self.transition.fillMode = kCAFillModeForwards
        self.transition.isRemovedOnCompletion = (self.counter == 2) ? true : false

        self.view.layer.add(self.transition, forKey: "transition2")
    })

    counter += 1
}
}

extension ViewController: CAAnimationDelegate {

func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
    animateCurlPage(start: 0.35, end: 0.32, duration: 0.2)
    animated = true
}
}

Here is the result of the code:

enter image description here

I hope you will not add a new gif again :D ! Cheers !

Edit: You should add the gifs before my answer, now it looks like I added a wrong solution for your good question.

For page curl animation and spring animation you need to execute two animations in the same time, so you need an animation group to be able to handle them and also one of the most important thing is to have different key for each animation. In the current example if you use the same key: transition for both animations, only a single animation will be executed and usually, the last one.

You can play a bit the animation parameters, I just added some arbitrary values here.

@IBAction func animate(_ sender: Any) {

    let animationGroup = CAAnimationGroup()
    animationGroup.duration = 5
    animationGroup.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionLinear)
    animationGroup.animations = [animateCurlPage(), animateSpringTransition()]

    view.layer.add(animationGroup, forKey: "animation")
}

func animateCurlPage() -> CAAnimation {
    let transition = CATransition()
    transition.type = "pageCurl"
    transition.subtype = kCATransitionFromRight
    transition.duration = 1
    view.layer.add(transition, forKey: "transition")
    return transition
}

func animateSpringTransition() -> CAAnimation{
    let transitionX = CASpringAnimation(keyPath: "position.y")
    transitionX.duration = 0.5
    transitionX.fromValue = view.layer.position.y
    transitionX.toValue = view.layer.position.y - 60

    transitionX.damping = 5.0
    transitionX.initialVelocity = 1.0
    transitionX.stiffness = 20.0
    transitionX.beginTime = CACurrentMediaTime()
    view.layer.add(transitionX, forKey: "transitionX")
    return transitionX
}

Here is the result: enter image description here

like image 97
Adela Toderici Avatar answered Dec 02 '25 04:12

Adela Toderici



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!