为什么UIViewPropertyAnimator会因自动布局而崩溃,但使用框架时却不会崩溃?

时间:2019-05-30 15:04:41

标签: swift autolayout uiviewpropertyanimator

我确定这是一个简单的解决方法,但是我一生都看不到它,所以我向您道歉!

我正在将一张小卡片从屏幕底部移动到一个动画状态,使其占据几乎所有屏幕。

这是代码: ViewDidLoad调用:

    let mealCardDetails = UIView()

    func setUpMealCardDetails() {
        mealCardDetails.frame = self.view.frame
        mealCardDetails.backgroundColor = .white
        mealCardDetails.layer.cornerRadius = 10.0
        mealCardDetails.layer.masksToBounds = true
        mealCardDetails.isHidden            = false
        view.addSubview(mealCardDetails)

        mealCardDetails.translatesAutoresizingMaskIntoConstraints = false
        mealCardDetailsLeadingAnchor               = mealCardDetails.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 32)
        mealCardDetailsLeadingAnchor?.isActive     = true

        mealCardDetailsTrailingAnchor              = mealCardDetails.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -32)
        mealCardDetailsTrailingAnchor?.isActive    = true

        mealCardDetailsTopAnchor                   = mealCardDetails.topAnchor.constraint(equalTo: view.topAnchor, constant: 400)
        mealCardDetailsTopAnchor?.isActive         = true

        mealCardDetailsBottomAnchor                = mealCardDetails.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -16)
        mealCardDetailsBottomAnchor?.isActive      = true

        mealCardDetails.layoutIfNeeded()
        mealCardDetails.layoutSubviews()

    }


我的约束发生变化(在gestureRecognizer中被调用):

    func adjustConstraintsCardTwo() {
        mealCardDetails.translatesAutoresizingMaskIntoConstraints = false
        mealCardDetailsLeadingAnchor?.isActive     = false
        mealCardDetailsLeadingAnchor               = mealCardDetails.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16)
        mealCardDetailsLeadingAnchor?.isActive     = true

        mealCardDetailsTrailingAnchor?.isActive    = false
        mealCardDetailsTrailingAnchor              = mealCardDetails.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16)
        mealCardDetailsTrailingAnchor?.isActive    = true

        mealCardDetailsTopAnchor?.isActive         = false
        mealCardDetailsTopAnchor                   = mealCardDetails.topAnchor.constraint(equalTo: view.topAnchor, constant: 24)
        mealCardDetailsTopAnchor?.isActive         = true

        mealCardDetailsBottomAnchor?.isActive      = false
        mealCardDetailsBottomAnchor                = mealCardDetails.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -16)
        mealCardDetailsBottomAnchor?.isActive      = true
    }

我的手势识别器:

        @objc func wasDraggedTest(_ gestureRecognizer: UIPanGestureRecognizer) {
            let translation = gestureRecognizer.translation(in: self.view)
            switch gestureRecognizer.state {
            case .began:
                let swipeLocation = gestureRecognizer.location(in: self.mealCollectionView)
                        self.mealCardDetails.isHidden = false
                        self.adjustConstraintsCardTwo()
                        startInteractiveTransition(currentState: .expanded, duration: 0.9)
            case .changed:
                let popupOffset: CGFloat = (UIScreen.main.bounds.height)
                let fractionComplete = -translation.y / popupOffset
                updateInteractiveTransition(fractionCompleted: fractionComplete)
            case .ended:
                self.mealCollectionView.isHidden = true
            default:
                break
            }
        }

UIViewPropertyAnimator

 enum CardState {
            case expanded
            case collapsed
        }


        var runningAnimations = [UIViewPropertyAnimator]()
        var animationProgressWhenInterrupted:CGFloat = 0



        func animateTransition (currentState: CardState, duration: TimeInterval) {
            if runningAnimations.isEmpty {
                let frameAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1) {
                    switch currentState {
                    case .expanded:
//                        self.mealCollectionView.frame.origin.y = self.view.frame.height - 400
                        self.mealCardDetails.layoutIfNeeded()
                    case .collapsed:
                        self.mealCardDetails.layoutIfNeeded()
                    }
                }

                frameAnimator.addCompletion { _ in
                    self.runningAnimations.removeAll()
                }

                frameAnimator.startAnimation()
                runningAnimations.append(frameAnimator)

                let cornerRadiusAnimator = UIViewPropertyAnimator(duration: duration, curve: .linear) {
                    switch currentState {
                    case .expanded:
                        self.mealCardDetails.layer.cornerRadius = 12
                    case .collapsed:
                        self.mealCardDetails.layer.cornerRadius = 12
                    }
                }

                cornerRadiusAnimator.startAnimation()
                runningAnimations.append(cornerRadiusAnimator)


                let alphaAnimator = UIViewPropertyAnimator(duration: duration, curve: .linear) {
                    switch currentState {
                    case .expanded:
                        self.mealCollectionView.alpha = 0
                    case .collapsed:
                        self.mealCollectionView.alpha = 1
                    }
                }

                alphaAnimator.startAnimation()
                runningAnimations.append(alphaAnimator)
            }
        }

        func startInteractiveTransition(currentState: CardState, duration: TimeInterval) {
            if runningAnimations.isEmpty {
                animateTransition(currentState: currentState, duration: duration)
            }
            for animator in runningAnimations {
                animator.pauseAnimation()
                animationProgressWhenInterrupted = animator.fractionComplete
            }
        }

        func updateInteractiveTransition(fractionCompleted:CGFloat) {
            for animator in runningAnimations {
                animator.fractionComplete = fractionCompleted + animationProgressWhenInterrupted
            }
        }

        func continueInteractiveTransition (){
            for animator in runningAnimations {
                animator.continueAnimation(withTimingParameters: nil, durationFactor: 0)
            }
        }

该应用程序崩溃了,我得到了这个错误: 由于未捕获的异常“ NSInternalInconsistencyException”而终止应用程序,原因:“释放已暂停或停止的属性动画器是错误的。属性动画制作者必须完成动画制作,或者必须明确停止并完成才能释放它们。'

我用Google搜索了它,并建议实现最终条件,但是如果您使用框架而不是自动布局,则该应用程序不会运行任何问题。有人对可能出什么问题有任何建议吗?

编辑: 如果我删除:

self.runningAnimations.removeAll()

它不再崩溃,但是它仍然不能在状态之间进行动画处理,因此我仍然认为问题出在我的自动布局实现中。

编辑2:可能是导致崩溃的结束条件(因为调用了完成处理程序)。但是,当我对卡片进行动画处理时,它会似乎立即崩溃,但是也许只是将卡片“动画化”至放大状态(它会直接跳到最终的动画帧,而不会随着时间的推移实际放大卡片),然后崩溃,所以也许我有两个看起来像一个的问题?

谢谢

0 个答案:

没有答案