我确定这是一个简单的解决方法,但是我一生都看不到它,所以我向您道歉!
我正在将一张小卡片从屏幕底部移动到一个动画状态,使其占据几乎所有屏幕。
这是代码: 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:可能是导致崩溃的结束条件(因为调用了完成处理程序)。但是,当我对卡片进行动画处理时,它会似乎立即崩溃,但是也许只是将卡片“动画化”至放大状态(它会直接跳到最终的动画帧,而不会随着时间的推移实际放大卡片),然后崩溃,所以也许我有两个看起来像一个的问题?
谢谢