CABasicAnimation 在隐式动画之后运行
CABasicAnimation runs after Implicit Animation
我希望图层的行为如下:
相反,它的行为如下:
卡片翻转动画是由应用在 CAAnimationGroup
中的两个 CABasicAnimation
创建的。发生不正确的旋转效果是因为 CALayer
属性 更改中的隐式动画首先运行,然后我在 CABasicAnimation
中指定的动画运行。如何停止 运行 中的隐式动画,以便只运行我指定的动画?
相关代码如下:
class ViewController: UIViewController {
var simpleLayer = CALayer()
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
self.view.addGestureRecognizer(tap)
simpleLayer.frame = CGRect(origin: CGPoint(x: view.bounds.width / 2 - 50, y: view.bounds.height / 2 - 50), size: CGSize(width: 100, height: 100))
simpleLayer.backgroundColor = UIColor.blackColor().CGColor
view.layer.addSublayer(simpleLayer)
}
func handleTap() {
let xRotation = CABasicAnimation(keyPath: "transform.rotation.x")
xRotation.toValue = 0
xRotation.byValue = M_PI
let yRotation = CABasicAnimation(keyPath: "transform.rotation.y")
yRotation.toValue = 0
yRotation.byValue = M_PI
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.y")
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.x")
let group = CAAnimationGroup()
group.animations = [xRotation, yRotation]
group.duration = 0.6
group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
simpleLayer.addAnimation(group, forKey: nil)
}
}
您正在创建 2 个单独的动画并将它们应用到一个动画组中。当您这样做时,它们将作为 2 个离散步骤应用。
看来这不是你想要的。如果不是,则不要创建 2 个单独的动画,一个在 transform.rotation.x 上,另一个在 transform.rotation.y 上。相反,将两个更改连接到转换矩阵并将更改的转换矩阵应用为单个动画。
@LucasTizma 的答案是正确的。
用 CATransaction.begin(); CATransaction.setDisableActions(true)
和 CATransaction.commit()
包围您的动画。这将 disable the implicit animation 并使 CAAnimationGroup
正确动画。
这是最终结果:
这是Swift 3:
中的重要代码片段
CATransaction.begin()
CATransaction.setDisableActions(true)
let xRotation = CABasicAnimation(keyPath: "transform.rotation.x")
xRotation.toValue = 0
xRotation.byValue = M_PI
let yRotation = CABasicAnimation(keyPath: "transform.rotation.y")
yRotation.toValue = 0
yRotation.byValue = M_PI
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.x")
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.y")
let group = CAAnimationGroup()
group.animations = [xRotation, yRotation]
simpleLayer.add(group, forKey: nil)
CATransaction.commit()
这是带有 iOS 应用程序的所描绘动画的完整代码:
class ViewController: UIViewController {
var simpleLayer = CALayer()
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
self.view.addGestureRecognizer(tap)
let ratio: CGFloat = 1 / 5
let viewWidth = view.bounds.width
let viewHeight = view.bounds.height
let layerWidth = viewWidth * ratio
let layerHeight = viewHeight * ratio
let rect = CGRect(origin: CGPoint(x: viewWidth / 2 - layerWidth / 2,
y: viewHeight / 2 - layerHeight / 2),
size: CGSize(width: layerWidth, height: layerHeight))
let topRightPoint = CGPoint(x: rect.width, y: 0)
let bottomRightPoint = CGPoint(x: rect.width, y: rect.height)
let topLeftPoint = CGPoint(x: 0, y: 0)
let linePath = UIBezierPath()
linePath.move(to: topLeftPoint)
linePath.addLine(to: topRightPoint)
linePath.addLine(to: bottomRightPoint)
linePath.addLine(to: topLeftPoint)
let maskLayer = CAShapeLayer()
maskLayer.path = linePath.cgPath
simpleLayer.frame = rect
simpleLayer.backgroundColor = UIColor.black.cgColor
simpleLayer.mask = maskLayer
// Smooth antialiasing
// * Convert the layer to a simple bitmap that's stored in memory
// * Saves CPU cycles during complex animations
// * Rasterization is set to happen during the animation and is disabled afterwards
simpleLayer.rasterizationScale = UIScreen.main.scale
view.layer.addSublayer(simpleLayer)
}
func handleTap() {
CATransaction.begin()
CATransaction.setDisableActions(true)
CATransaction.setCompletionBlock({
self.simpleLayer.shouldRasterize = false
})
simpleLayer.shouldRasterize = true
let xRotation = CABasicAnimation(keyPath: "transform.rotation.x")
xRotation.toValue = 0
xRotation.byValue = M_PI
let yRotation = CABasicAnimation(keyPath: "transform.rotation.y")
yRotation.toValue = 0
yRotation.byValue = M_PI
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.x")
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.y")
let group = CAAnimationGroup()
group.animations = [xRotation, yRotation]
group.duration = 1.2
group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
simpleLayer.add(group, forKey: nil)
CATransaction.commit()
}
}
我希望图层的行为如下:
相反,它的行为如下:
卡片翻转动画是由应用在 CAAnimationGroup
中的两个 CABasicAnimation
创建的。发生不正确的旋转效果是因为 CALayer
属性 更改中的隐式动画首先运行,然后我在 CABasicAnimation
中指定的动画运行。如何停止 运行 中的隐式动画,以便只运行我指定的动画?
相关代码如下:
class ViewController: UIViewController {
var simpleLayer = CALayer()
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
self.view.addGestureRecognizer(tap)
simpleLayer.frame = CGRect(origin: CGPoint(x: view.bounds.width / 2 - 50, y: view.bounds.height / 2 - 50), size: CGSize(width: 100, height: 100))
simpleLayer.backgroundColor = UIColor.blackColor().CGColor
view.layer.addSublayer(simpleLayer)
}
func handleTap() {
let xRotation = CABasicAnimation(keyPath: "transform.rotation.x")
xRotation.toValue = 0
xRotation.byValue = M_PI
let yRotation = CABasicAnimation(keyPath: "transform.rotation.y")
yRotation.toValue = 0
yRotation.byValue = M_PI
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.y")
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.x")
let group = CAAnimationGroup()
group.animations = [xRotation, yRotation]
group.duration = 0.6
group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
simpleLayer.addAnimation(group, forKey: nil)
}
}
您正在创建 2 个单独的动画并将它们应用到一个动画组中。当您这样做时,它们将作为 2 个离散步骤应用。
看来这不是你想要的。如果不是,则不要创建 2 个单独的动画,一个在 transform.rotation.x 上,另一个在 transform.rotation.y 上。相反,将两个更改连接到转换矩阵并将更改的转换矩阵应用为单个动画。
@LucasTizma 的答案是正确的。
用 CATransaction.begin(); CATransaction.setDisableActions(true)
和 CATransaction.commit()
包围您的动画。这将 disable the implicit animation 并使 CAAnimationGroup
正确动画。
这是最终结果:
这是Swift 3:
中的重要代码片段CATransaction.begin()
CATransaction.setDisableActions(true)
let xRotation = CABasicAnimation(keyPath: "transform.rotation.x")
xRotation.toValue = 0
xRotation.byValue = M_PI
let yRotation = CABasicAnimation(keyPath: "transform.rotation.y")
yRotation.toValue = 0
yRotation.byValue = M_PI
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.x")
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.y")
let group = CAAnimationGroup()
group.animations = [xRotation, yRotation]
simpleLayer.add(group, forKey: nil)
CATransaction.commit()
这是带有 iOS 应用程序的所描绘动画的完整代码:
class ViewController: UIViewController {
var simpleLayer = CALayer()
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
self.view.addGestureRecognizer(tap)
let ratio: CGFloat = 1 / 5
let viewWidth = view.bounds.width
let viewHeight = view.bounds.height
let layerWidth = viewWidth * ratio
let layerHeight = viewHeight * ratio
let rect = CGRect(origin: CGPoint(x: viewWidth / 2 - layerWidth / 2,
y: viewHeight / 2 - layerHeight / 2),
size: CGSize(width: layerWidth, height: layerHeight))
let topRightPoint = CGPoint(x: rect.width, y: 0)
let bottomRightPoint = CGPoint(x: rect.width, y: rect.height)
let topLeftPoint = CGPoint(x: 0, y: 0)
let linePath = UIBezierPath()
linePath.move(to: topLeftPoint)
linePath.addLine(to: topRightPoint)
linePath.addLine(to: bottomRightPoint)
linePath.addLine(to: topLeftPoint)
let maskLayer = CAShapeLayer()
maskLayer.path = linePath.cgPath
simpleLayer.frame = rect
simpleLayer.backgroundColor = UIColor.black.cgColor
simpleLayer.mask = maskLayer
// Smooth antialiasing
// * Convert the layer to a simple bitmap that's stored in memory
// * Saves CPU cycles during complex animations
// * Rasterization is set to happen during the animation and is disabled afterwards
simpleLayer.rasterizationScale = UIScreen.main.scale
view.layer.addSublayer(simpleLayer)
}
func handleTap() {
CATransaction.begin()
CATransaction.setDisableActions(true)
CATransaction.setCompletionBlock({
self.simpleLayer.shouldRasterize = false
})
simpleLayer.shouldRasterize = true
let xRotation = CABasicAnimation(keyPath: "transform.rotation.x")
xRotation.toValue = 0
xRotation.byValue = M_PI
let yRotation = CABasicAnimation(keyPath: "transform.rotation.y")
yRotation.toValue = 0
yRotation.byValue = M_PI
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.x")
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.y")
let group = CAAnimationGroup()
group.animations = [xRotation, yRotation]
group.duration = 1.2
group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
simpleLayer.add(group, forKey: nil)
CATransaction.commit()
}
}