如何解决如何使用 UIViewPropertyAnimator 实现三模式转换?
我尝试使用 UIViewPropertyAnimator 实现三种模式转换,我能够成功实现两种模式转换,但无法执行中间模式向下动画。以下 GIF 是目前实现的效果。
func setPanGesture() -> InstantPanGestureRecognizer {
let recognizer = InstantPanGestureRecognizer()
recognizer.addTarget(self,action: #selector(popupViewPanned(recognizer:)))
return recognizer
}
func intialSetUp() {
topSmallView.alpha = 0.0
topCalendarView.alpha = 0.0
popViewTopConstraint.constant = self.popviewIntialTopConstraint()
tapAndSwipeButton.addGestureRecognizer(setPanGesture())
topCalendarView.addGestureRecognizer(setPanGesture())
topSmallView.addGestureRecognizer(setPanGesture())
}
@objc private func popupViewPanned(recognizer: UIPanGestureRecognizer) {
let veLocity = recognizer.veLocity(in: self.view.superview)
print("VeLocity \(veLocity)")
switch recognizer.state {
case .began:
panDidBegan(recognizer: recognizer)
case .changed:
panDidChanged(recognizer: recognizer)
case .ended:
panDidEnd(recognizer: recognizer)
default:
()
}
}
//MARK:- Panning Helper
func panDidBegan(recognizer : UIPanGestureRecognizer) {
var animationState : AnimationState = currentState.opposite
if currentState == .secondary {
let veLocity = recognizer.veLocity(in: self.view.superview)
let isverticalGesture = abs(veLocity.y) > abs(veLocity.x)
if (isverticalGesture) {
if (veLocity.y > 0) {
animationState = .primary
} else {
animationState = .closed
}
}
}else if currentState == .primary {
let veLocity = recognizer.veLocity(in: self.view.superview)
let isverticalGesture = abs(veLocity.y) > abs(veLocity.x)
if (isverticalGesture) {
if (veLocity.y > 0) {
animationState = .primary
} else {
animationState = .secondary
}
}
}
animateTransitionIfNeeded(to: animationState,duration: 1)
// pause all animations,since the next event may be a pan changed
runningAnimators.forEach { $0.pauseAnimation() }
// keep track of each animator's progress
animationProgress = runningAnimators.map { $0.fractionComplete }
}
func panDidChanged(recognizer : UIPanGestureRecognizer) {
var translationView : UIView
if currentState == .primary {
translationView = topSmallView
}else if currentState == .secondary {
translationView = topCalendarView
}else{
translationView = view
}
let translation = recognizer.translation(in: translationView)
var fraction = -translation.y / translationView.frame.size.height
print("fraction\(fraction)")
// adjust the fraction for the current state and reversed state
if currentState == .primary || currentState == .secondary {
fraction *= -1
}
if runningAnimators.count > 0 {
if runningAnimators[0].isReversed { fraction *= -1 }
}
// apply the new fraction
for (index,animator) in runningAnimators.enumerated() {
let fractionCom = (fraction + animationProgress[index])
print("fractionCom\(fractionCom)")
animator.fractionComplete = fractionCom
}
}
func panDidEnd(recognizer : UIPanGestureRecognizer) {
var translationView : UIView
if currentState == .primary {
translationView = topSmallView
}else if currentState == .secondary {
translationView = topCalendarView
}else{
translationView = view
}
// variable setup
let yVeLocity = recognizer.veLocity(in: translationView).y
let shouldClose = yVeLocity > 0
// if there is no motion,continue all animations and exit early
if yVeLocity == 0 {
runningAnimators.forEach { $0.continueAnimation(withTimingParameters: nil,durationFactor: 0) }
return
}
// reverse the animations based on their current state and pan motion
if runningAnimators.count > 0 {
switch currentState {
case .primary:
if !shouldClose && !runningAnimators[0].isReversed { runningAnimators.forEach { $0.isReversed = !$0.isReversed } }
if shouldClose && runningAnimators[0].isReversed { runningAnimators.forEach { $0.isReversed = !$0.isReversed } }
case .secondary:
if !shouldClose && !runningAnimators[0].isReversed { runningAnimators.forEach { $0.isReversed = !$0.isReversed } }
if shouldClose && runningAnimators[0].isReversed { runningAnimators.forEach { $0.isReversed = !$0.isReversed } }
case .closed:
if shouldClose && !runningAnimators[0].isReversed { runningAnimators.forEach { $0.isReversed = !$0.isReversed } }
if !shouldClose && runningAnimators[0].isReversed { runningAnimators.forEach { $0.isReversed = !$0.isReversed } }
}
}
// continue all animations
runningAnimators.forEach { $0.continueAnimation(withTimingParameters: nil,durationFactor: 0) }
}
//MARK:- View Animator Helper
/// Animates the transition,if the animation is not already running.
private func animateTransitionIfNeeded(to state: AnimationState,duration: TimeInterval) {
// ensure that the animators array is empty (which implies new animations need to be created)
guard runningAnimators.isEmpty else { return }
// an animator for the transition
let transitionAnimator = UIViewPropertyAnimator(duration: duration,dampingRatio: 1.0,animations: {
switch state {
case .primary:
self.topBaseViewTopConstraint.constant = self.fullOpenStateBaseViewYosition()
self.topCalendarView.alpha = 0
self.topSmallView.alpha = 1
break
case .secondary:
self.popViewTopConstraint.constant = 30.0
self.swipeButtonBottomConstraint.constant = 0.0
self.topBaseViewTopConstraint.constant = 0.0
self.topCalendarView.alpha = 1
self.topSmallView.alpha = 0
break
case .closed:
self.popViewTopConstraint.constant = self.popviewIntialTopConstraint()
self.swipeButtonBottomConstraint.constant = 60.0
self.topCalendarView.alpha = 0
self.topSmallView.alpha = 0
break
}
self.view.layoutIfNeeded()
})
// the transition completion block
transitionAnimator.addCompletion { position in
// update the state
switch position {
case .start:
self.currentState = state.opposite
case .end:
self.currentState = state
case .current:
()
@unkNown default:
break
}
// manually reset the constraint positions
switch self.currentState {
case .primary:
self.topBaseViewTopConstraint.constant = self.fullOpenStateBaseViewYosition()
self.topCalendarView.alpha = 0
self.topSmallView.alpha = 1
case .secondary:
self.popViewTopConstraint.constant = 30.0
self.topBaseViewTopConstraint.constant = 0.0
self.swipeButtonBottomConstraint.constant = 0.0
self.topCalendarView.alpha = 1
self.topSmallView.alpha = 0
case .closed:
self.popViewTopConstraint.constant = self.popviewIntialTopConstraint()
self.swipeButtonBottomConstraint.constant = 60.0
self.topCalendarView.alpha = 0
self.topSmallView.alpha = 0
}
// remove all running animators
self.runningAnimators.removeAll()
}
transitionAnimator.startAnimation()
runningAnimators.append(transitionAnimator)
}
如何使用 UIViewPropertyAnimator 实现这个动画?。非常感谢 谢谢。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。