我有一个集合视图,用于保存带有图像视图的单元格。当用户按下图像视图(使用touchesBegan)时触发动画,并在用户释放时触发另一个动画(使用touchesEnded)。
只有当我按下我的点击然后释放(延迟点击)时,动画才能完美运行,但是当我快速点击时,动画会跳跃,就好像持续时间设置为0一样。
我认为问题是因为集合视图是滚动视图的子类,而scrollViews“通过启动计时器暂时拦截触摸事件,并且在计时器触发之前,查看触摸手指是否进行任何移动。如果计时器在没有显着位置变化的情况下触发,滚动视图将跟踪事件发送到内容视图的触摸子视图。“
https://developer.apple.com/documentation/uikit/uiscrollview#//apple_ref/doc/uid/TP40006922
从我可以收集到的内容来看,我认为如果点击比触摸计时器更快,则从集合视图中触摸拦截会导致动画出现问题。当我使用常规视图而不是集合视图作为超级视图进行测试时,动画效果很好,不需要延迟点击。
如果是这种情况,那么动画是如何触发快速点击的呢?而且,如何在不使用延迟点击的情况下触发动画?
如果不是这种情况,那么这个问题可能是什么原因?
这是我的动画和触摸代码:
func animateClickerAndBallPoint(newXpositionForClicker: CGFloat, newXpositionForBallPoint: CGFloat, ballPoint: UIImageView) {
UIView.animate(withDuration: 0.1) {
self.frame.origin.x = newXpositionForClicker
ballPoint.frame.origin.x = newXpositionForBallPoint
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let ballPoint = self.ballPoint else {return}
self.animateClickerAndBallPoint(newXpositionForClicker: 288, newXpositionForBallPoint: 11, ballPoint: ballPoint)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let ballPoint = self.ballPoint else {return}
if isInWritingMode == true {
animateClickerAndBallPoint(newXpositionForClicker: 306, newXpositionForBallPoint: 26, ballPoint: ballPoint)
isInWritingMode = false
} else {
animateClickerAndBallPoint(newXpositionForClicker: 297, newXpositionForBallPoint: 17, ballPoint: ballPoint)
isInWritingMode = true
}
}
答案 0 :(得分:2)
作为替代方案,您可以考虑挂钩按钮touchesBegan
和touchesEnded
,而不是自己做beginTracking
和endTracking
。
例如,您可以将按钮子类化并提供您想要的任何动画:
class AnimatedButton: UIButton {
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
UIView.animate(withDuration: 0.25) {
self.transform = .init(scaleX: 0.8, y: 0.8)
}
return true
}
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
UIView.animate(withDuration: 0.25) {
self.transform = .identity
}
}
}
产量:
或者,如果你想根据单元格本身的部分来做,你可以挂钩到集合视图的“突出显示”机制,如https://stackoverflow.com/a/45664054/1271826所示。
顺便说一下,你假设问题是容器视图弄乱了。你100%确定这是问题吗?这可能是一个基本的动画问题。 E.g。例如,如果您在第一个动画仍在运行时开始第二个动画,它将无法完成第一个动画,而是立即从动画中期的任何地方立即开始第二个动画(并且在现代动画中) iOS版本,使用当前正在运行的任何速度)并转换到新目的地。
例如,这里有两个视图,我正在以相同的距离向下播放一秒钟,然后再向上播放另一秒钟。但是对于右边的视图,我在第一个动画中开始第二个动画0.1秒(即中断第一个动画):
正如您所看到的,因为第二个示例正在中断您的动画,所以它看起来只是抢回来。
我认为在这种情况下不太可能,但如果您使用自动布局,则必须小心。如果您执行任何触发自动布局引擎重新应用其约束的事情(这实际上可能是任何UI操作,例如在某些不相关的标签中设置文本一样无害),这将阻止您正在进行的任何动画和将视图捕捉回到受限制的位置。
如果使用自动布局布置视图,您可能还需要考虑使用自动布局设置动画。例如,不是调整frame
(或其他),而是为约束创建IBOutlet
,更改该约束的constant
,然后将调用设置为layoutIfNeeded
。
最重要的是,您可能想知道是否可以验证问题是否与触摸事件有关,而不是某些无关的动画问题。
不幸的是,您的示例中没有足够的内容来诊断问题的根源。您可以考虑创建MVCE, a minimal, verifiable, and complete example of the problem。我建议创建一个没有集合视图和另一个集合视图的MVCE,这样你就可以确认集合视图是否真的是问题的根源。但是,直到我们能够重现您的问题,我们很难帮您解决问题。
答案 1 :(得分:1)
在scrollviews
中播放动画时遇到了同样的问题。
我通过在动画中使用该参数来修复它:UIViewAnimationOptions.allowUserInteraction
所以你的动画块会像那样结束:
UIView.animate(withDuration: duration,
delay: 0,
usingSpringWithDamping: CGFloat(0.30),
initialSpringVelocity: CGFloat(10.0),
options: UIViewAnimationOptions.allowUserInteraction,
animations: {
applyWhatEverTransform()
},completion: completion)
我有点猜测你的问题,因为我们没有你的代码。但是,当然,如果您使用不同类型的动画,则无法使用;)
此外,如果这没有帮助。为了帮助您进行调试,您可以尝试禁用滚动集合视图以查看拦截触摸事件的事件。
答案 2 :(得分:1)
您是否尝试过delaysContentTouches = false
?
https://developer.apple.com/documentation/uikit/uiscrollview/1619398-delayscontenttouches
告诉scrollView / collectionView不要延迟对单元格的触摸。当我开始点击它们时,我立即为我做了响应细胞。也没有制作我的滚动车。