Swift 如何使用 属性 带有平移手势的动画器
Swift how to use property animator with pan gesture
所以我有一个 UIView
附加了一个 PanGestureRecognizer
允许我上下移动视图。当我向上移动视图时,我想 减少按钮的 alpha,当我 向下移动视图时,我想将其增加到正常值 。
我曾尝试在按钮卡入某个位置时单独为按钮设置动画,但这会破坏我的 PropertyAnimator
。
我目前的实现工作发现,前提是我的手指在视图上,因为这个 returns 来自识别器的 .changed
状态。但我也有实现,当视图在沿 y 轴 的某个点释放时,将视图捕捉到位。问题是它没有达到 .changed 状态,因此改变了我的 hideAnimator.fractionComplete
在动画中途离开按钮。
初始化属性动画师方法
func initPropertyAnimator() {
hideAnimator = UIViewPropertyAnimator(duration: 0.18, curve: .easeInOut, animations: {
self.requestButton.alpha = 0
})
}
识别器状态为 panGesture(recognizer: UIPanGestureRecognizer)
let currentY = self.frame.minY
switch recognizer.state {
case .began:
print("Began")
case .changed:
// Property animator
let offset: CGFloat = window!.frame.height-194
let percentage: CGFloat = (offset-currentY)/100
print(percentage)
hideAnimator?.fractionComplete = CGFloat(percentage)
case .ended:
// Snap back below 80 (y)
if currentY < 80 || currentY > 80 && currentY < halfWayPoint
{
self.animator?.stopAnimation(true)
UIView.animate(withDuration:0.62, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations:
{
recognizer.view!.frame = CGRect(x: 0, y: 80, width: self.frame.width, height: self.frame.height)
self.requestButton.alpha = 0
self.houseView.frame = CGRect(x: 16, y: 87, width: self.boxWidth, height: 68)
self.officeView.frame = CGRect(x: 16, y: 171, width: self.boxWidth, height: 68)
self.carView.frame = CGRect(x: 16, y: 255, width: self.boxWidth, height: 68)
self.gardenView.frame = CGRect(x: 16, y: 339, width: self.boxWidth, height: 68)
}, completion: { (true) in
})
}
// Snap back above partial (y)
if currentY > partialY || currentY < partialY && currentY > halfWayPoint
{
self.animator?.stopAnimation(true)
UIView.animate(withDuration:0.62, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations:
{
recognizer.view!.frame = CGRect(x: 0, y: partialY, width: self.frame.width, height: self.frame.height)
self.requestButton.alpha = 1
self.houseView.frame = CGRect(x: 16, y: 87+200, width: self.boxWidth, height: 68)
self.officeView.frame = CGRect(x: 16, y: 171+200, width: self.boxWidth, height: 68)
self.carView.frame = CGRect(x: 16, y: 255+200, width: self.boxWidth, height: 68)
self.gardenView.frame = CGRect(x: 16, y: 339+200, width: self.boxWidth, height: 68)
}, completion: { (true) in
})
}
我通过添加 布尔值 来检查视图当前是否展开然后根据 true 或 false 解决了这个问题我加载相应的动画。我知道这不是最好的做事方式,因为您可以 return 动画到其原始位置而无需编写太多代码。无论如何,它有效,所以我会使用它。
顺便说一句,我非常欢迎任何可以帮助改进此代码的人,它确实需要一些 TLC。
这是我的 处理我的 panGestureRecogniser
的整个方法
// MARK: - Pan gesture
@objc func panGesture(recognizer: UIPanGestureRecognizer) {
let window = UIApplication.shared.keyWindow
let translation = recognizer.translation(in: self)
let currentY = self.frame.minY
let partialY = (window?.frame.height)!-194
let halfWayPoint = ((window?.frame.height)!/2)-40
self.frame = CGRect(x: 0, y: currentY + translation.y, width: self.frame.width, height: self.frame.height)
recognizer.setTranslation(CGPoint.zero, in: self)
switch recognizer.state {
case .began:
print("Began")
if isExpanded
{
animator = UIViewPropertyAnimator(duration: 0.18, curve: .easeInOut, animations: {
self.requestButton.alpha = 1
self.houseView.alpha = 0
self.officeView.alpha = 0
self.gardenView.alpha = 0
self.carView.alpha = 0
self.houseView.frame = CGRect(x: 16, y: 87+200, width: self.boxWidth, height: 68)
self.officeView.frame = CGRect(x: 16, y: 171+200, width: self.boxWidth, height: 68)
self.carView.frame = CGRect(x: 16, y: 255+200, width: self.boxWidth, height: 68)
self.gardenView.frame = CGRect(x: 16, y: 339+200, width: self.boxWidth, height: 68)
})
self.animator?.isReversed = true
}
else
{
animator = UIViewPropertyAnimator(duration: 0.18, curve: .easeInOut, animations: {
self.requestButton.alpha = 0
self.houseView.alpha = 1
self.officeView.alpha = 1
self.gardenView.alpha = 1
self.carView.alpha = 1
self.houseView.frame = CGRect(x: 16, y: 87, width: self.boxWidth, height: 68)
self.officeView.frame = CGRect(x: 16, y: 171, width: self.boxWidth, height: 68)
self.carView.frame = CGRect(x: 16, y: 255, width: self.boxWidth, height: 68)
self.gardenView.frame = CGRect(x: 16, y: 339, width: self.boxWidth, height: 68)
})
self.animator?.isReversed = false
}
animator?.startAnimation()
animator?.pauseAnimation()
case .changed:
// Property animator
let offset: CGFloat = window!.frame.height-194
let fraction: CGFloat = (offset-currentY)/4
let percentage = fraction/100
print(percentage)
animator?.fractionComplete = CGFloat(percentage)
// Prevent scrolling up past y:0
if currentY <= 0
{
self.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
}
case .ended:
// Snap to 80 (y) (expanded)
if currentY < 80 || currentY > 80 && currentY < halfWayPoint
{
self.animator?.stopAnimation(true)
UIView.animate(withDuration:0.62, delay: 0.0, usingSpringWithDamping: 0.62, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations:
{
recognizer.view!.frame = CGRect(x: 0, y: 80, width: self.frame.width, height: self.frame.height)
self.requestButton.alpha = 0
self.houseView.alpha = 1
self.officeView.alpha = 1
self.gardenView.alpha = 1
self.carView.alpha = 1
self.houseView.frame = CGRect(x: 16, y: 87, width: self.boxWidth, height: 68)
self.officeView.frame = CGRect(x: 16, y: 171, width: self.boxWidth, height: 68)
self.carView.frame = CGRect(x: 16, y: 255, width: self.boxWidth, height: 68)
self.gardenView.frame = CGRect(x: 16, y: 339, width: self.boxWidth, height: 68)
}, completion: { (true) in
self.isExpanded = true
})
}
// Snap back to partial (y) (original position)
if currentY > partialY || currentY < partialY && currentY > halfWayPoint
{
self.animator?.stopAnimation(true)
UIView.animate(withDuration:0.62, delay: 0.0, usingSpringWithDamping: 0.62, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations:
{
recognizer.view!.frame = CGRect(x: 0, y: partialY, width: self.frame.width, height: self.frame.height)
self.requestButton.alpha = 1
self.houseView.alpha = 0
self.officeView.alpha = 0
self.gardenView.alpha = 0
self.carView.alpha = 0
self.houseView.frame = CGRect(x: 16, y: 87+200, width: self.boxWidth, height: 68)
self.officeView.frame = CGRect(x: 16, y: 171+200, width: self.boxWidth, height: 68)
self.carView.frame = CGRect(x: 16, y: 255+200, width: self.boxWidth, height: 68)
self.gardenView.frame = CGRect(x: 16, y: 339+200, width: self.boxWidth, height: 68)
}, completion: {(true) in
self.isExpanded = false
})
}
case .cancelled:
print("Cancelled")
case .failed:
print("Failed")
default:
print("Default")
}
}
所以我有一个 UIView
附加了一个 PanGestureRecognizer
允许我上下移动视图。当我向上移动视图时,我想 减少按钮的 alpha,当我 向下移动视图时,我想将其增加到正常值 。
我曾尝试在按钮卡入某个位置时单独为按钮设置动画,但这会破坏我的 PropertyAnimator
。
我目前的实现工作发现,前提是我的手指在视图上,因为这个 returns 来自识别器的 .changed
状态。但我也有实现,当视图在沿 y 轴 的某个点释放时,将视图捕捉到位。问题是它没有达到 .changed 状态,因此改变了我的 hideAnimator.fractionComplete
在动画中途离开按钮。
初始化属性动画师方法
func initPropertyAnimator() {
hideAnimator = UIViewPropertyAnimator(duration: 0.18, curve: .easeInOut, animations: {
self.requestButton.alpha = 0
})
}
识别器状态为 panGesture(recognizer: UIPanGestureRecognizer)
let currentY = self.frame.minY
switch recognizer.state {
case .began:
print("Began")
case .changed:
// Property animator
let offset: CGFloat = window!.frame.height-194
let percentage: CGFloat = (offset-currentY)/100
print(percentage)
hideAnimator?.fractionComplete = CGFloat(percentage)
case .ended:
// Snap back below 80 (y)
if currentY < 80 || currentY > 80 && currentY < halfWayPoint
{
self.animator?.stopAnimation(true)
UIView.animate(withDuration:0.62, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations:
{
recognizer.view!.frame = CGRect(x: 0, y: 80, width: self.frame.width, height: self.frame.height)
self.requestButton.alpha = 0
self.houseView.frame = CGRect(x: 16, y: 87, width: self.boxWidth, height: 68)
self.officeView.frame = CGRect(x: 16, y: 171, width: self.boxWidth, height: 68)
self.carView.frame = CGRect(x: 16, y: 255, width: self.boxWidth, height: 68)
self.gardenView.frame = CGRect(x: 16, y: 339, width: self.boxWidth, height: 68)
}, completion: { (true) in
})
}
// Snap back above partial (y)
if currentY > partialY || currentY < partialY && currentY > halfWayPoint
{
self.animator?.stopAnimation(true)
UIView.animate(withDuration:0.62, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations:
{
recognizer.view!.frame = CGRect(x: 0, y: partialY, width: self.frame.width, height: self.frame.height)
self.requestButton.alpha = 1
self.houseView.frame = CGRect(x: 16, y: 87+200, width: self.boxWidth, height: 68)
self.officeView.frame = CGRect(x: 16, y: 171+200, width: self.boxWidth, height: 68)
self.carView.frame = CGRect(x: 16, y: 255+200, width: self.boxWidth, height: 68)
self.gardenView.frame = CGRect(x: 16, y: 339+200, width: self.boxWidth, height: 68)
}, completion: { (true) in
})
}
我通过添加 布尔值 来检查视图当前是否展开然后根据 true 或 false 解决了这个问题我加载相应的动画。我知道这不是最好的做事方式,因为您可以 return 动画到其原始位置而无需编写太多代码。无论如何,它有效,所以我会使用它。
顺便说一句,我非常欢迎任何可以帮助改进此代码的人,它确实需要一些 TLC。
这是我的 处理我的 panGestureRecogniser
// MARK: - Pan gesture
@objc func panGesture(recognizer: UIPanGestureRecognizer) {
let window = UIApplication.shared.keyWindow
let translation = recognizer.translation(in: self)
let currentY = self.frame.minY
let partialY = (window?.frame.height)!-194
let halfWayPoint = ((window?.frame.height)!/2)-40
self.frame = CGRect(x: 0, y: currentY + translation.y, width: self.frame.width, height: self.frame.height)
recognizer.setTranslation(CGPoint.zero, in: self)
switch recognizer.state {
case .began:
print("Began")
if isExpanded
{
animator = UIViewPropertyAnimator(duration: 0.18, curve: .easeInOut, animations: {
self.requestButton.alpha = 1
self.houseView.alpha = 0
self.officeView.alpha = 0
self.gardenView.alpha = 0
self.carView.alpha = 0
self.houseView.frame = CGRect(x: 16, y: 87+200, width: self.boxWidth, height: 68)
self.officeView.frame = CGRect(x: 16, y: 171+200, width: self.boxWidth, height: 68)
self.carView.frame = CGRect(x: 16, y: 255+200, width: self.boxWidth, height: 68)
self.gardenView.frame = CGRect(x: 16, y: 339+200, width: self.boxWidth, height: 68)
})
self.animator?.isReversed = true
}
else
{
animator = UIViewPropertyAnimator(duration: 0.18, curve: .easeInOut, animations: {
self.requestButton.alpha = 0
self.houseView.alpha = 1
self.officeView.alpha = 1
self.gardenView.alpha = 1
self.carView.alpha = 1
self.houseView.frame = CGRect(x: 16, y: 87, width: self.boxWidth, height: 68)
self.officeView.frame = CGRect(x: 16, y: 171, width: self.boxWidth, height: 68)
self.carView.frame = CGRect(x: 16, y: 255, width: self.boxWidth, height: 68)
self.gardenView.frame = CGRect(x: 16, y: 339, width: self.boxWidth, height: 68)
})
self.animator?.isReversed = false
}
animator?.startAnimation()
animator?.pauseAnimation()
case .changed:
// Property animator
let offset: CGFloat = window!.frame.height-194
let fraction: CGFloat = (offset-currentY)/4
let percentage = fraction/100
print(percentage)
animator?.fractionComplete = CGFloat(percentage)
// Prevent scrolling up past y:0
if currentY <= 0
{
self.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
}
case .ended:
// Snap to 80 (y) (expanded)
if currentY < 80 || currentY > 80 && currentY < halfWayPoint
{
self.animator?.stopAnimation(true)
UIView.animate(withDuration:0.62, delay: 0.0, usingSpringWithDamping: 0.62, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations:
{
recognizer.view!.frame = CGRect(x: 0, y: 80, width: self.frame.width, height: self.frame.height)
self.requestButton.alpha = 0
self.houseView.alpha = 1
self.officeView.alpha = 1
self.gardenView.alpha = 1
self.carView.alpha = 1
self.houseView.frame = CGRect(x: 16, y: 87, width: self.boxWidth, height: 68)
self.officeView.frame = CGRect(x: 16, y: 171, width: self.boxWidth, height: 68)
self.carView.frame = CGRect(x: 16, y: 255, width: self.boxWidth, height: 68)
self.gardenView.frame = CGRect(x: 16, y: 339, width: self.boxWidth, height: 68)
}, completion: { (true) in
self.isExpanded = true
})
}
// Snap back to partial (y) (original position)
if currentY > partialY || currentY < partialY && currentY > halfWayPoint
{
self.animator?.stopAnimation(true)
UIView.animate(withDuration:0.62, delay: 0.0, usingSpringWithDamping: 0.62, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations:
{
recognizer.view!.frame = CGRect(x: 0, y: partialY, width: self.frame.width, height: self.frame.height)
self.requestButton.alpha = 1
self.houseView.alpha = 0
self.officeView.alpha = 0
self.gardenView.alpha = 0
self.carView.alpha = 0
self.houseView.frame = CGRect(x: 16, y: 87+200, width: self.boxWidth, height: 68)
self.officeView.frame = CGRect(x: 16, y: 171+200, width: self.boxWidth, height: 68)
self.carView.frame = CGRect(x: 16, y: 255+200, width: self.boxWidth, height: 68)
self.gardenView.frame = CGRect(x: 16, y: 339+200, width: self.boxWidth, height: 68)
}, completion: {(true) in
self.isExpanded = false
})
}
case .cancelled:
print("Cancelled")
case .failed:
print("Failed")
default:
print("Default")
}
}