Sina
Sina

Reputation: 869

pageCurl animation interactive with touches

I'm looking for a way to indicate a page curl animation on an UIView that interactive with touch(Began/Moved/Ended) like this

Note:

  1. I can't use UIPageController. The animation should be applied to the UIView.
  2. The interaction between the animation and the start of the touch, touch movement and touch end is very important. Exactly like video

Sample Code but dont work with touch:

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.

    BackBtn.layer.cornerRadius = 5.0

    AnimationBtn.layer.cornerRadius = 5.0

    transition.delegate = self
    transition.duration = 1.5
    transition.startProgress = 0
    transition.endProgress = 1
    transition.type = CATransitionType(string: "pageCurl") as String
    transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    transition.fillMode = kCAFillModeBoth
    transition.isRemovedOnCompletion = false
}

in touch moved:

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

    super.touchesMoved(touches, with: event)

    if let touch = touches.first {

        let endPosition = touch.location(in: touch.view)

        differenceX = startPosition.x - endPosition.x

        differenceY = endPosition.y - startPosition.y

        transition.subtype = kCATransitionFromRight

        touch.view!.layer.add(transition, forKey: kCATransition)

        webView.scrollView.contentOffset = CGPoint(x: nextPage + differenceX, y: 0)
   }
}

Upvotes: 3

Views: 249

Answers (1)

Sina
Sina

Reputation: 869

I found answer. I just need to change the transition.startProgress and transition.endProgress.

Sample code:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesBegan(touches, with: event)

    calculatePageCount()

    if let touch = touches.first {

        startPosition = touch.location(in: self.view)

        endPosition = startPosition

        previousPositionX = startPosition.x

        print("start x: \(startPosition.x), start y: \(startPosition.y)")

        transition.startProgress = 0.0

        if index == 0 && startPosition.x > (screenWidth / 2) {

            transition.endProgress = 1.0 - Float(startPosition.x / screenWidth)
            transition.subtype = kCATransitionFromRight

            self.view.layer.add(transition, forKey: kCATransition)
        } else if index != 0 {
            if index != (pageCounter - 1) && startPosition.x > (screenWidth / 2) {
                if self.view.layer.animationKeys() != nil {
                    self.view.layer.removeAllAnimations()
                }

                transition.endProgress = 1.0 - Float(startPosition.x / screenWidth)
                transition.subtype = kCATransitionFromRight
                self.view.layer.add(transition, forKey: kCATransition)
            } else if startPosition.x < (screenWidth / 2) {
                if self.view.layer.animationKeys() != nil {
                    self.view.layer.removeAllAnimations()
                }

                transition.endProgress = Float(startPosition.x / screenWidth)
                transition.subtype = kCATransitionFromLeft
                self.view.layer.add(transition, forKey: kCATransition)
            } else {
                if self.view.layer.animationKeys() != nil {
                    self.view.layer.removeAllAnimations()
                }
            }
        } else {
            if self.view.layer.animationKeys() != nil {
                self.view.layer.removeAllAnimations()
            }
        }
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesMoved(touches, with: event)

    if let touch = touches.first {

        endPosition = touch.location(in: touch.view)

        print("end x: \(endPosition.x), end y: \(endPosition.y)")

        differenceX = startPosition.x - endPosition.x

        differenceY = endPosition.y - startPosition.y

        let differencePosition = endPosition.x - previousPositionX

        previousPositionX = endPosition.x

        print("difference x: \(differenceX)")

        if self.view.layer.animationKeys() != nil {

            transition.startProgress = transition.endProgress

            if differenceX > 0 {

                differencePosition < 0 ? (transition.endProgress = transition.endProgress + Float((abs(differencePosition) / screenWidth))) : (transition.endProgress = transition.endProgress - Float((abs(differencePosition) / screenWidth)))

                self.view.layer.removeAllAnimations()
                self.view.layer.add(transition, forKey: kCATransition)
            } else {

                differencePosition > 0 ? (transition.endProgress = transition.endProgress + Float((abs(differencePosition) / screenWidth))) : (transition.endProgress = transition.endProgress - Float((abs(differencePosition) / screenWidth)))

                self.view.layer.removeAllAnimations()
                self.view.layer.add(transition, forKey: kCATransition)
            }
        }
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesEnded(touches, with: event)

    print("touch ended")

    if self.view.layer.animationKeys() != nil {

        if startPosition.x == endPosition.x {

            transition.startProgress = transition.endProgress
            transition.endProgress = 0

            self.view.layer.removeAllAnimations()
            self.view.layer.add(transition, forKey: kCATransition)
        } else {

            if differenceX > 0 {

                if differenceX > (screenWidth / 2) {

                    if index < (pageCounter - 1) {
                        index += 1
                    }
                    transition.startProgress = transition.endProgress
                    transition.endProgress = 1

                    self.view.layer.removeAllAnimations()
                    self.view.layer.add(transition, forKey: kCATransition)
                } else {
                    transition.endProgress = 0

                    self.view.layer.removeAllAnimations()
                    self.view.layer.add(transition, forKey: kCATransition)
                }
            } else {

                if abs(differenceX) > (screenWidth / 2) {
                    if index > 0 {
                        index -= 1

                        transition.startProgress = transition.endProgress
                        transition.endProgress = 1

                        self.view.layer.removeAllAnimations()
                        self.view.layer.add(transition, forKey: kCATransition)
                    } else {
                        transition.endProgress = 0

                        self.view.layer.removeAllAnimations()
                        self.view.layer.add(transition, forKey: kCATransition)
                    }
                } else {

                    transition.endProgress = 0

                    self.view.layer.removeAllAnimations()
                    self.view.layer.add(transition, forKey: kCATransition)
                }
            }
        }
    }
    nextPage = CGFloat(index) * webView.scrollView.bounds.size.width
    webView.scrollView.contentOffset = CGPoint(x: nextPage, y: 0)
}

func calculatePageCount() {

    pageCounter = Int((webView.scrollView.contentSize.width / webView.scrollView.bounds.size.width).rounded())
}

Upvotes: 3

Related Questions