我想我必须将CGRect转换为一个对象以将其传递给fromValue?
这是我尝试的方式,但它不起作用:
CABasicAnimation *frameAnimation = [CABasicAnimation animationWithKeyPath:@"frame"];
frameAnimation.duration = 2.5;
frameAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
frameAnimation.fromValue = [NSValue valueWithCGRect:myLayer.frame];
frameAnimation.toValue = [NSValue valueWithCGRect:theNewFrameRect];
[myLayer addAnimation:frameAnimation forKey:@"MLC"];
答案 0 :(得分:87)
CALayer的frame属性是派生属性,取决于图层的位置,anchorPoint,边界和变换。您应该为位置或边界设置动画,而不是为框架设置动画,具体取决于您要完成的效果。
要移动图层,您可以为position
:
-(void)moveLayer:(CALayer*)layer to:(CGPoint)point
{
// Prepare the animation from the current position to the new position
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.fromValue = [layer valueForKey:@"position"];
// NSValue/+valueWithPoint:(NSPoint)point is available on Mac OS X
// NSValue/+valueWithCGPoint:(CGPoint)point is available on iOS
// comment/uncomment the corresponding lines depending on which platform you're targeting
// Mac OS X
animation.toValue = [NSValue valueWithPoint:NSPointFromCGPoint(point)];
// iOS
//animation.toValue = [NSValue valueWithCGPoint:point];
// Update the layer's position so that the layer doesn't snap back when the animation completes.
layer.position = point;
// Add the animation, overriding the implicit animation.
[layer addAnimation:animation forKey:@"position"];
}
要调整图层大小,您可以为bounds
参数设置动画:
-(void)resizeLayer:(CALayer*)layer to:(CGSize)size
{
// Prepare the animation from the old size to the new size
CGRect oldBounds = layer.bounds;
CGRect newBounds = oldBounds;
newBounds.size = size;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds"];
// NSValue/+valueWithRect:(NSRect)rect is available on Mac OS X
// NSValue/+valueWithCGRect:(CGRect)rect is available on iOS
// comment/uncomment the corresponding lines depending on which platform you're targeting
// Mac OS X
animation.fromValue = [NSValue valueWithRect:NSRectFromCGRect(oldBounds)];
animation.toValue = [NSValue valueWithRect:NSRectFromCGRect(newBounds)];
// iOS
//animation.fromValue = [NSValue valueWithCGRect:oldBounds];
//animation.toValue = [NSValue valueWithCGRect:newBounds];
// Update the layer's bounds so the layer doesn't snap back when the animation completes.
layer.bounds = newBounds;
// Add the animation, overriding the implicit animation.
[layer addAnimation:animation forKey:@"bounds"];
}
如果需要同时移动和调整图层大小,可以使用CAAnimationGroup组合这些动画。
答案 1 :(得分:6)
我们可以更改“bounds”和“position”的属性来为其设置动画,例如
-(void)handleTap2:(UITapGestureRecognizer *)recognizer {
UIImageView *vw = (UIImageView *)[recognizer view];
CGPoint startPoint = CGPointMake(vw.frame.size.width/2+vw.frame.origin.x, vw.frame.size.height/2+vw.frame.origin.y);
CGPoint endPoint = CGPointMake(160, 240);
CGRect startBounds = vw.bounds;
CGRect stopBounds = self.view.bounds;
layer = [CALayer layer];
layer.frame = self.view.frame;
layer.contents = (id)[vw.image CGImage];
[self.view.window.layer addSublayer:layer];
CABasicAnimation * baseAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
baseAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
baseAnimation.fromValue = [NSValue valueWithCGPoint:startPoint] ;
baseAnimation.toValue = [NSValue valueWithCGPoint:endPoint] ;
CABasicAnimation * boundsAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"];
boundsAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
boundsAnimation.fromValue = [NSValue valueWithCGRect:startBounds] ; boundsAnimation.toValue = [NSValue valueWithCGRect:stopBounds] ;
CAAnimationGroup * group =[CAAnimationGroup animation];
group.removedOnCompletion=NO; group.fillMode=kCAFillModeForwards;
group.animations =[NSArray arrayWithObjects:baseAnimation, boundsAnimation, nil];
group.duration = 0.7;
[layer addAnimation:group forKey:@"frame"];
}
答案 2 :(得分:3)
问题是古董,但无论如何我都会回答。
帧属性不可动画。您必须为其他属性设置动画。您还必须禁用隐式动画。
let updatedBounds = ...
let animation = CABasicAnimation(keyPath: "bounds")
animation.duration = 0.5
//it's better to start animation from presentation layer in case there is already animation going on
animation.fromValue = customLayer.presentation()?.bounds
animation.toValue = updatedBounds
customLayer.add(animation, forKey: nil)
//disable implicit animation for thoose properties
CATransaction.begin()
CATransaction.setDisableActions(true)
//update properties so they will be updated at the end of animation
customLayer.bounds = updatedBounds
customLayer.position = originalRect.origin
customLayer.anchorPoint = CGPoint(x: 0, y: 0)
CATransaction.commit()
答案 3 :(得分:2)
这是一个简单,完整的例子,可以帮助某人。
只需在课程上调用.slideUp()
,它就会向上滑动。
class Slidey: YourViewClass {
func slideUp() {
print("\n\n SLIDE")
let FF = layer.position
var TT = FF
TT.y -= 100
print(FF)
print(TT)
CATransaction.begin()
CATransaction.setDisableActions(true)
CATransaction.setCompletionBlock{ [weak self] in
print("DONE")
}
let a = CABasicAnimation(keyPath: "position")
a.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
a.isCumulative = false
a.autoreverses = false
a.isRemovedOnCompletion = true
a.repeatCount = 0
a.fromValue = FF
a.toValue = TT
a.duration = 0.70
layer.add(a, forKey: nil)
CATransaction.commit()
}
}
答案 4 :(得分:0)
快速扩展4
import UIKit
extension CALayer {
func moveTo(point: CGPoint, animated: Bool) {
if animated {
let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = value(forKey: "position")
animation.toValue = NSValue(cgPoint: point)
animation.fillMode = .forwards
self.position = point
add(animation, forKey: "position")
} else {
self.position = point
}
}
func resize(to size: CGSize, animated: Bool) {
let oldBounds = bounds
var newBounds = oldBounds
newBounds.size = size
if animated {
let animation = CABasicAnimation(keyPath: "bounds")
animation.fromValue = NSValue(cgRect: oldBounds)
animation.toValue = NSValue(cgRect: newBounds)
animation.fillMode = .forwards
self.bounds = newBounds
add(animation, forKey: "bounds")
} else {
self.bounds = newBounds
}
}
func resizeAndMove(frame: CGRect, animated: Bool, duration: TimeInterval = 0) {
if animated {
let positionAnimation = CABasicAnimation(keyPath: "position")
positionAnimation.fromValue = value(forKey: "position")
positionAnimation.toValue = NSValue(cgPoint: CGPoint(x: frame.midX, y: frame.midY))
let oldBounds = bounds
var newBounds = oldBounds
newBounds.size = frame.size
let boundsAnimation = CABasicAnimation(keyPath: "bounds")
boundsAnimation.fromValue = NSValue(cgRect: oldBounds)
boundsAnimation.toValue = NSValue(cgRect: newBounds)
let groupAnimation = CAAnimationGroup()
groupAnimation.animations = [positionAnimation, boundsAnimation]
groupAnimation.fillMode = .forwards
groupAnimation.duration = duration
groupAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
self.frame = frame
add(groupAnimation, forKey: "frame")
} else {
self.frame = frame
}
}
}
答案 5 :(得分:-6)
我猜您需要更改最后一行才能使其正常工作:
[myLayer addAnimation:frameAnimation forKey:@"frame"];
您还可以为图层设置一个动作,以便使用动画对所有帧更改进行动画处理:
CABasicAnimation *frameAnimation = [CABasicAnimation animation];
frameAnimation.duration = 2.5;
frameAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
myLayer.actions = [NSDictionary dictionaryWithObjectsAndKeys:frameAnimation, @"frame", nil];
在CALayer的actionForKey:
方法参考中,您可以找到图层如何查找动画以对其属性进行动画处理。