这里是我试图重复的代码,根据Apple WWDC,但使用自动收费:
extension AugmentedReallityViewController {
@objc func handlePan(recognizer: UIPanGestureRecognizer) {
// // hide languages and units anyway
// moveUnitView(show: false)
// moveLanguageView(show: false)
//
// let isNowExpanded = settingsPanelState == SettingsPanelState.expanded
// let newState = isNowExpanded ? SettingsPanelState.collapsed : SettingsPanelState.expanded
//
// switch recognizer.state {
// case .began:
// startInteractiveTransition(state: newState, duration: 1)
// isLastPanelUpdateToReachTheNewState = true // just in case, but we should change this property later
// case .changed:
// let translation = recognizer.translation(in: viewSettings)
// let fractionComplete = translation.y / viewSettings.frame.size.height
//
// // we will use this property when interaction ends
// if fractionComplete != 0 { // if it's == 0 , we need to use prev data
// isLastPanelUpdateToReachTheNewState = (newState == SettingsPanelState.expanded && fractionComplete < 0) || (newState == SettingsPanelState.collapsed && fractionComplete > 0)
// }
//
// updateInteractiveTransition(fractionComplete: fractionComplete)
// case .ended:
// continueInteractiveTransition(cancel: !isLastPanelUpdateToReachTheNewState)
// default:
// break
// }
}
@objc func handleSettingsTap() {
// hide languages and units anyway
moveUnitView(show: false)
moveLanguageView(show: false)
let isNowExpanded = settingsPanelState == SettingsPanelState.expanded
let newState = isNowExpanded ? SettingsPanelState.collapsed : SettingsPanelState.expanded
animateOrReverseRunningTransition(state: newState, duration: 10)
}
// perform all animations with animators if not already running
private func animateTransitionIfNeeded(state: SettingsPanelState, duration: TimeInterval) {
if runningAnimators.isEmpty {
// // define constraint for frame animation
// // update constraints
// switch state {
// case .expanded:
// constraint_settingsView_bottom.constant = 0
// case .collapsed:
// constraint_settingsView_bottom.constant = -constraint_height_settingViewWhitePart.constant
// }
// animate that
let frameAnimator = UIViewPropertyAnimator(duration: duration, curve: .linear, animations: { [weak self] in
if let strongSelf = self {
// define constraint for frame animation
// update constraints
switch state {
case .expanded:
strongSelf.constraint_settingsView_bottom.constant = 0
case .collapsed:
strongSelf.constraint_settingsView_bottom.constant = -(strongSelf.constraint_height_settingViewWhitePart.constant)
}
}
self?.view.layoutIfNeeded()
})
frameAnimator.startAnimation()
runningAnimators.append(frameAnimator)
frameAnimator.addCompletion({ [weak self] (position) in
if position == UIViewAnimatingPosition.end { // need to remove this animator from array
if let index = self?.runningAnimators.index(of: frameAnimator) {
print("removed animator because of completion")
self?.runningAnimators.remove(at: index)
// we can change state to a new one
self?.settingsPanelState = state
}
else {
print("animator completion with state = \(position)")
}
}
})
}
}
// starts transition if neccessary or reverses it on tap
private func animateOrReverseRunningTransition(state: SettingsPanelState, duration: TimeInterval) {
if runningAnimators.isEmpty { // start transition from start to end
animateTransitionIfNeeded(state: state, duration: duration)
}
else { // reverse all animators
for animator in runningAnimators {
animator.stopAnimation(true)
animator.isReversed = !animator.isReversed
// test
print("tried to reverse")
}
}
}
// called only on pan .begin
// starts transition if neccessary and pauses (on pan .begin)
private func startInteractiveTransition(state: SettingsPanelState, duration: TimeInterval) {
animateTransitionIfNeeded(state: state, duration: duration)
for animator in runningAnimators {
animator.pauseAnimation()
// save progress of any item
progressWhenInterrupted = animator.fractionComplete
}
}
// scrubs transition on pan .changed
private func updateInteractiveTransition(fractionComplete: CGFloat) {
for animator in runningAnimators {
animator.fractionComplete = fractionComplete + progressWhenInterrupted
}
}
// continue or reverse transition on pan .ended
private func continueInteractiveTransition(cancel: Bool) {
for animator in runningAnimators {
// need to continue or reverse
if !cancel {
let timing = UICubicTimingParameters(animationCurve: .easeOut)
animator.continueAnimation(withTimingParameters: timing, durationFactor: 0)
}
else {
animator.isReversed = true
}
}
}
private func addPanGustureRecognizerToSettings() {
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(AugmentedReallityViewController.handlePan(recognizer:)))
// panGestureRecognizer.cancelsTouchesInView = false
viewSettings.addGestureRecognizer(panGestureRecognizer)
}
private func addTapGestureRecognizerToSettings() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(AugmentedReallityViewController.handleSettingsTap))
tapGestureRecognizer.cancelsTouchesInView = false
viewSettingsTopTriangle.addGestureRecognizer(tapGestureRecognizer)
}
}现在我只是在测试踢踏舞姿势。有两个主要问题:
1) Tap识别器在动画过程中不能正常工作。但是在苹果WWDC中,他们改变了帧(而不是像我这样的约束),并且点击识别器工作得很好。
2)如果我改变了反向属性,那么约束就会改变得非常糟糕。我有多余的条子等等
( 3)在动画块和动画内部都尝试了改变约束的方法。这真的不重要,工作一样
,有什么帮助,如何用自动收费?或者至少如何使用框架,但是我的视图控制器是基于自动收费的,所以无论如何,我对这个底层视图都有限制。
发布于 2017-10-05 15:38:20
当您在动画中使用autolayout时,如下所示:
layoutIfNeeded():
UIView.animate(withDuration: 1,动画:{ self.view.layoutIfNeeded() })在使用UIViewPropertyAnimator时也是如此--更改动画块中的约束。例如:
self.view.layoutIfNeeded()
someConstraint.constant = 0
self.view.setNeedsLayout()
let animator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut) {
self.view.layoutIfNeeded()
}
animator.startAnimation()这是因为layoutIfNeeded()执行实际的布局-它计算受影响视图的帧。因此,如果直接设置框架,则在动画块中设置它们。但是,Autolayout为您设置框架-因此,您需要的是告诉autolayout在动画块中设置它们(就像您要做的那样,如果您要直接设置它们)。layoutIfNeeded()调用正是这样做的-它告诉自动收费引擎计算和设置新的帧。
关于反转的:
虽然我没有足够的经验来100%确定,但我希望简单地设置动画师逆转是不够的。因为您在启动动画之前应用了这些约束,然后告诉autolayout根据这些约束更新框架--我假设当您反转动画器时,还需要反转驱动动画的约束。
动画师只是将视图动画到新的框架中。但是,无论反转与否,新的约束仍然有效,不管您是否反转了动画师。因此,在动画师完成之后,如果以后自动输出再次显示视图,我将期望视图进入当前活动约束设置的位置。简单地说:动画师动画帧的变化,但不是约束自己。这意味着逆转动画师反转帧,但它不会逆转约束--一旦自动输出完成另一个布局周期,它们将再次被应用。
发布于 2019-10-04 09:56:40
设置self.view.layoutIfNeeded()动画发生的重要事项
private func animateCard(with topOffset: CGFloat) {
let animator = UIViewPropertyAnimator(duration: 1, curve: .easeOut)
animator.addAnimations {
self.topCardConstraint?.constant = topOffset
self.view.layoutIfNeeded()
}
animator.startAnimation()
}https://stackoverflow.com/questions/46588815
复制相似问题