pageCurl 动画与触摸交互

pageCurl animation interactive with touches

我正在寻找一种方法来在 UIView 上指示与触摸交互的卷页动画 (Began/Moved/Ended) like this

注:

  1. 我无法使用 UIPageController。动画应应用于 UIView.
  2. 动画与触摸开始、触摸移动和触摸结束的交互非常重要。跟视频一模一样

示例代码但不适用于触摸:

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
}

触摸感动:

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

我找到了答案。我只需要更改 transition.startProgresstransition.endProgress.

示例代码:

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