我有一组要设置动画的元素。我在索引中每增加一个延迟。但是,某些元素会同时进行动画处理(通常一次是两个)。
我不确定这是因为for循环不是以恒定的速度进行迭代,还是主线程对其进行了太多调用?
*注意-翻转卡不是问题。如果我只设置cell.alpha = 0,问题仍然存在。
有问题的Gif- https://imgur.com/a/0e8JXyw
private func animateCells() {
if collectionView.visibleCells.count < indexToFlip { return }
let numberOfCards = collectionView.visibleCells.count
var currentIndex = 1
var delayNextFlipMiliSeconds = 0
for section in 0 ..< collectionView.numberOfSections {
for row in 0 ..< collectionView.numberOfItems(inSection: section) {
guard let cell = collectionView.cellForItem(at: IndexPath(row: row, section: section)) as? CardCell else { continue }
print(delayNextFlipMiliSeconds)
print(NSDate().timeIntervalSince1970)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(delayNextFlipMiliSeconds)) {
cell.flipCard() {
currentIndex += 1
if currentIndex == numberOfCards {
UIView.animate(withDuration: 0.5, animations: {
self.playButton.alpha = 1
})
}
}
}
delayNextFlipMiliSeconds += 200
}
}
}
调试打印。.
0
1547749398.849406
200
1547749398.850255
400
1547749398.850312
600
1547749398.850347
800
1547749398.8503752
1000
1547749398.850401
1200
1547749398.850429
1400
1547749398.850459
1600
1547749398.850482
1800
1547749398.850504
2000
1547749398.850525
2200
1547749398.850559
2400
1547749398.850597
2600
1547749398.85063
2800
1547749398.850657
3000
1547749398.850702
答案 0 :(得分:1)
DispatchQueue.main是一个串行队列,可确保按照将任务添加到队列的顺序执行任务。但是,dispatch_async在添加到队列后返回,并且可能尚未完成,其余代码(for循环)开始执行。
发生的事情是,“ for”循环将多个代码(任务)块放入主队列中,这些块将按顺序执行,但是执行时间可能取决于处理器的可用性。某些任务可能比其他任务更快地获得计划。调度程序在运行时调度任务,无法预测。这就是为什么您看到它没有定期执行的原因。
您可以尝试
Timer.scheduledTimer(withTimeInterval: delayNextFlipMiliSeconds, repeats: false) { (timer) in
DispatchQueue.main.sync {
//Your Code
}
}.fire()
使用DispatchQueue.main.sync将确保首先执行“您的代码”,然后将执行其余代码。但是,从用户的角度来看,使用DispatchQueue.main.sync也会减慢UI的速度,但是我认为这可以忽略不计。
答案 1 :(得分:0)
不能将UIView.animate()与完成处理程序一起使用吗?这样,您可以在第一个动画完成后直接传递下一个动画。
答案 2 :(得分:0)
我决定不关心GCD或for循环时间,而改用计时器。效果很好。
private func animateCells() {
var cells: [CardCell] = []
for section in 0 ..< collectionView.numberOfSections {
for row in 0 ..< collectionView.numberOfItems(inSection: section) {
guard let cell = collectionView.cellForItem(at: IndexPath(row: row, section: section)) as? CardCell else { continue }
cells.append(cell)
}
}
var animationIndex = 0
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { (timer) in
cells[animationIndex].flipCard()
animationIndex += 1
if animationIndex == cells.count {
UIView.animate(withDuration: 0.5, animations: {
self.playButton.alpha = 1
})
timer.invalidate()
}
}.fire()
}