我正在尝试创建一个不定加载器,其中一个栏从左向右移动。它有点像您在 Google Apps 中看到的旋转器,但后来是一个栏。这篇博客是一篇很棒的文章,展示了如何使用 UIBezierPaths 和 CABasicAnimation 创建这样的旋转器:
http://blog.matthewcheok.com/design-teardown-spinning-indicator/
但就我而言,我想对酒吧做同样的事情。因此,有一条从左到右的线,就像在微调器中一样,我还以较小的延迟对中风开始进行动画处理,使其看起来沿着线移动并在最后赶上它。 当它到达末尾时,我希望它从右向左返回,等等。 所有这些都使用easeIn 和easeOut。而且我不希望线条到达末端时不可见,一小部分应该始终保持可见。
为了让我的解释更清楚,这就是我想要的:
我知道我似乎已经有了我想要的东西,但我使用丑陋的延迟代码创建了这个 gif,但它有一半时间无法正常工作。
因此,继续,不能使用 CABasicAnimation 的自动反转属性,因为我对中风结束和中风开始都进行了动画处理,所以我有两个想法:
现在,我已经走了很远了,但棘手的部分是我必须切换图层。无论我尝试什么,我总是看到闪烁。我知道我必须使用表示层并在添加动画组之前或之后设置正确的值。
我使用 CATransaction.setCompletionBlock 来了解何时到达左侧或右侧部分,然后转向另一个方向。
以下是我编写的代码的一些部分:
UIBezierPaths:
let start:CGPoint = .init(x: 0, y: 0)
let end:CGPoint = .init(x: frame.width, y: 0)
let pathLeft = UIBezierPath()
pathLeft.move(to: start)
pathLeft.addLine(to: end)
self.barLayerLeft.path = pathLeft.cgPath
let pathRight = UIBezierPath()
pathRight.move(to: end)
pathRight.addLine(to: start)
self.barLayerRight.path = pathRight.cgPath
设置描边开始和描边结束动画和一组
let strokeStartAnimation: CAAnimation = {
let animation = CABasicAnimation(keyPath: "strokeStart")
animation.fromValue = 0
animation.toValue = 0.99
animation.beginTime = 0.3
animation.duration = 1
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
return animation
}()
let strokeEndAnimation: CAAnimation = {
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
animation.beginTime = 0
animation.duration = 1.3
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
return animation
}()
组和图层
let groupedAnimation:CAAnimationGroup = CAAnimationGroup()
groupedAnimation.duration = 1.4
groupedAnimation.animations = [self.strokeStartAnimation, self.strokeEndAnimation]
self.barLayerLeft.lineWidth = 4
self.barLayerLeft.lineCap = .round
self.barLayerLeft.strokeColor = AppStyler.mainColor.cgColor
self.layer.addSublayer(self.barLayerLeft)
self.barLayerRight.lineWidth = 4
self.barLayerRight.lineCap = .round
self.barLayerRight.strokeColor = AppStyler.mainColor.cgColor
self.layer.addSublayer(self.barLayerRight)
向左动画(包括设置最终位置,以便动画线将准确地保持在动画完成时的位置,并删除从右到左的栏)
self.barLayerLeft.strokeEnd = 1
self.barLayerLeft.strokeStart = 0.01
self.barLayerRight.strokeEnd = 1
self.barLayerRight.strokeStart = 0
self.barLayerLeft.add(self.groupedAnimation, forKey: "groupLeft")
CATransaction.setCompletionBlock{ [weak self] in
self.animateRight()
}
向右动画(包括上面的位置)
self.barLayerRight.strokeEnd = 1
self.barLayerRight.strokeStart = 0.01
self.barLayerLeft.strokeEnd = 1
self.barLayerLeft.strokeStart = 0
self.barLayerRight.add(self.groupedAnimation, forKey: "groupRight")
CATransaction.setCompletionBlock{ [weak self] in
self.animateLeft()
}
我已经尝试使用“CATransaction.setDisableActions”来切换图层,而不会看到这样的闪烁:
CATransaction.begin()
CATransaction.setDisableActions(true)
self.barLayerLeft.strokeEnd = 0.01
self.barLayerLeft.strokeStart = 0
self.barLayerRight.strokeEnd = 1
self.barLayerRight.strokeStart = 0
CATransaction.commit()
但我无法让它工作......
所以,我的主要问题是。我上面的想法真的可以不闪烁吗?或者我需要完全使用其他东西......?有没有更简单/更好的方法来实现我想要的?
顺便说一句,如果有什么不清楚或者我需要发布更多代码,请告诉我!
我会使用遮罩和单个移动层来解决这个问题:
let container = CALayer()
container.frame = CGRect(x: 10, y: 10, width: 200, height: 10)
container.borderColor = UIColor.black.cgColor
container.borderWidth = 1
container.cornerRadius = 5
container.masksToBounds = true
view.layer.addSublayer(container)
let bar = CALayer()
bar.frame = container.bounds
bar.anchorPoint = CGPoint(x: 0, y: 0.5)
bar.position = CGPoint(x: -195, y: 5)
bar.backgroundColor = UIColor.blue.cgColor
container.addSublayer(bar)
let animation = CABasicAnimation(keyPath: "position.x")
animation.fromValue = bar.position.x
animation.toValue = 195
animation.autoreverses = true
animation.repeatCount = .infinity
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
animation.duration = 2
bar.add(animation, forKey: nil)
看起来像这样,但没那么可怕,因为它不是 GIF:
在工作结束时暂停会更简单,因为它是单个动画。