Ios 如何使用动画制作曲线/圆弧动画?
我有一个删除项目的用户界面,我想模仿iOS邮件中的“移动到文件夹”效果。小字母图标被“抛出”到文件夹中的效果。我的会被扔到垃圾桶里 我尝试在层上使用Ios 如何使用动画制作曲线/圆弧动画?,ios,caanimation,Ios,Caanimation,我有一个删除项目的用户界面,我想模仿iOS邮件中的“移动到文件夹”效果。小字母图标被“抛出”到文件夹中的效果。我的会被扔到垃圾桶里 我尝试在层上使用CAAnimation实现它。就我在文档中所读到的内容而言,我应该能够设置byValue和toValue,并且动画应该插入这些值。我希望做一个小的曲线,所以项目通过一个点略高于和项目的开始位置的左侧 CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"p
CAAnimation
实现它。就我在文档中所读到的内容而言,我应该能够设置byValue
和toValue
,并且动画应该插入这些值。我希望做一个小的曲线,所以项目通过一个点略高于和项目的开始位置的左侧
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"position"];
[animation setDuration:2.0f];
[animation setRemovedOnCompletion:NO];
[animation setFillMode:kCAFillModeForwards];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseOut]];
[animation setFromValue:[NSValue valueWithCGPoint:fromPoint]];
[animation setByValue:[NSValue valueWithCGPoint:byPoint]];
[animation setToValue:[NSValue valueWithCGPoint:CGPointMake(512.0f, 800.0f)]];
[animation setRepeatCount:1.0];
我已经玩了一段时间,但在我看来,苹果意味着线性插值。
添加byValue不会计算漂亮的圆弧或曲线,也不会通过它设置项目动画
我将如何着手制作这样的动画
谢谢你的帮助。我知道怎么做了。可以分别设置X和Y的动画。如果在同一时间(下面2.0秒)设置它们的动画,并设置不同的计时功能,则会使其看起来像是在圆弧中移动,而不是从开始到结束值的直线。要调整圆弧,您需要设置不同的计时功能。但不确定CAAnimation是否支持任何“性感”计时功能
const CFTimeInterval DURATION = 2.0f;
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"position.y"];
[animation setDuration:DURATION];
[animation setRemovedOnCompletion:NO];
[animation setFillMode:kCAFillModeForwards];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
[animation setFromValue:[NSNumber numberWithDouble:400.0]];
[animation setToValue:[NSNumber numberWithDouble:0.0]];
[animation setRepeatCount:1.0];
[animation setDelegate:self];
[myview.layer addAnimation:animation forKey:@"animatePositionY"];
animation = [CABasicAnimation animationWithKeyPath:@"position.x"];
[animation setDuration:DURATION];
[animation setRemovedOnCompletion:NO];
[animation setFillMode:kCAFillModeForwards];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
[animation setFromValue:[NSNumber numberWithDouble:300.0]];
[animation setToValue:[NSNumber numberWithDouble:0.0]];
[animation setRepeatCount:1.0];
[animation setDelegate:self];
[myview.layer addAnimation:animation forKey:@"animatePositionX"];
编辑:
应该可以通过使用(由带有控制点的函数初始化的CAMediaTimingFunction:)更改计时函数
这是一条“三次贝塞尔曲线”。我相信谷歌在这里有答案。:-) 几天前我遇到了一个类似的问题,我用timer实现了它,如前所述,但不是
NSTimer
CADisplayLink
-这是用于此目的的计时器,因为它与应用程序的帧速率同步,并提供更平滑、更自然的动画。你可以在我的回答中看到我对它的实现。这项技术确实比CAAnimation
对动画提供了更多的控制,而且也不太复杂。
CAAnimation
无法绘制任何内容,因为它甚至不会重新绘制视图。它只会移动、变形和淡出已经绘制的内容。试试这个它肯定会解决您的问题,我在我的项目中使用过这个:
UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(10, 126, 320, 24)] autorelease];
label.text = @"Animate image into trash button";
label.textAlignment = UITextAlignmentCenter;
[label sizeToFit];
[scrollView addSubview:label];
UIImageView *icon = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"carmodel.png"]] autorelease];
icon.center = CGPointMake(290, 150);
icon.tag = ButtonActionsBehaviorTypeAnimateTrash;
[scrollView addSubview:icon];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.center = CGPointMake(40, 200);
button.tag = ButtonActionsBehaviorTypeAnimateTrash;
[button setTitle:@"Delete Icon" forState:UIControlStateNormal];
[button sizeToFit];
[button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:button];
[scrollView bringSubviewToFront:icon];
- (void)buttonClicked:(id)sender {
UIView *senderView = (UIView*)sender;
if (![senderView isKindOfClass:[UIView class]])
return;
switch (senderView.tag) {
case ButtonActionsBehaviorTypeExpand: {
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform"];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
anim.duration = 0.125;
anim.repeatCount = 1;
anim.autoreverses = YES;
anim.removedOnCompletion = YES;
anim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 1.0)];
[senderView.layer addAnimation:anim forKey:nil];
break;
}
case ButtonActionsBehaviorTypeAnimateTrash: {
UIView *icon = nil;
for (UIView *theview in senderView.superview.subviews) {
if (theview.tag != ButtonActionsBehaviorTypeAnimateTrash)
continue;
if ([theview isKindOfClass:[UIImageView class]]) {
icon = theview;
break;
}
}
if (!icon)
return;
UIBezierPath *movePath = [UIBezierPath bezierPath];
[movePath moveToPoint:icon.center];
[movePath addQuadCurveToPoint:senderView.center
controlPoint:CGPointMake(senderView.center.x, icon.center.y)];
CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
moveAnim.path = movePath.CGPath;
moveAnim.removedOnCompletion = YES;
CABasicAnimation *scaleAnim = [CABasicAnimation animationWithKeyPath:@"transform"];
scaleAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
scaleAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1, 0.1, 1.0)];
scaleAnim.removedOnCompletion = YES;
CABasicAnimation *opacityAnim = [CABasicAnimation animationWithKeyPath:@"alpha"];
opacityAnim.fromValue = [NSNumber numberWithFloat:1.0];
opacityAnim.toValue = [NSNumber numberWithFloat:0.1];
opacityAnim.removedOnCompletion = YES;
CAAnimationGroup *animGroup = [CAAnimationGroup animation];
animGroup.animations = [NSArray arrayWithObjects:moveAnim, scaleAnim, opacityAnim, nil];
animGroup.duration = 0.5;
[icon.layer addAnimation:animGroup forKey:nil];
break;
}
}
}
使用UIBezierPath
(如果您使用的是iOS 6或更高版本,请不要忘记链接,然后导入QuartzCore)
示例代码
您可以使用沿着路径的动画,非常方便,CAKeyframeAnimation
支持CGPath
,可以从UIBezierPath
获取。斯威夫特3
func animate(view : UIView, fromPoint start : CGPoint, toPoint end: CGPoint)
{
// The animation
let animation = CAKeyframeAnimation(keyPath: "position")
// Animation's path
let path = UIBezierPath()
// Move the "cursor" to the start
path.move(to: start)
// Calculate the control points
let c1 = CGPoint(x: start.x + 64, y: start.y)
let c2 = CGPoint(x: end.x, y: end.y - 128)
// Draw a curve towards the end, using control points
path.addCurve(to: end, controlPoint1: c1, controlPoint2: c2)
// Use this path as the animation's path (casted to CGPath)
animation.path = path.cgPath;
// The other animations properties
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = false
animation.duration = 1.0
animation.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseIn)
// Apply it
view.layer.add(animation, forKey:"trash")
}
理解UIBezierPath
贝塞尔路径(或者准确地说)的工作原理与你在photoshop、fireworks、sketch中找到的完全相同。。。它们有两个“控制点”,每个顶点一个。例如,我刚才制作的动画:
贝塞尔路径就是这样工作的。请参见,但基本上是两点将圆弧“拉”向某个方向
绘制路径
UIBezierPath
的一个很酷的功能是,您可以使用CAShapeLayer
在屏幕上绘制它们,从而帮助您可视化它将遵循的路径
// Drawing the path
let *layer = CAShapeLayer()
layer.path = path.cgPath
layer.strokeColor = UIColor.black.cgColor
layer.lineWidth = 1.0
layer.fillColor = nil
self.view.layer.addSublayer(layer)
改进原始示例
计算您自己的bezier路径的想法是,您可以使曲线完全动态,因此,动画可以基于多个因素更改它将要执行的曲线,而不是像我在示例中所做的那样仅进行硬编码,例如,可以按如下方式计算控制点:
// Calculate the control points
let factor : CGFloat = 0.5
let deltaX : CGFloat = end.x - start.x
let deltaY : CGFloat = end.y - start.y
let c1 = CGPoint(x: start.x + deltaX * factor, y: start.y)
let c2 = CGPoint(x: end.x , y: end.y - deltaY * factor)
最后一位代码使点与前一个图形相似,但数量可变,相对于点形成的三角形,乘以一个系数,该系数相当于“张力”值。您完全正确,使用
CABasicAnimation
设置位置动画会使其沿直线移动。还有一个类叫做CAKeyframeAnimation
,用于制作更高级的动画
值的数组
对于基本动画,您可以使用值数组
或完整的路径
来确定过程中的值,而不是toValue
、fromValue
和byValue
。如果要先向侧面然后向下设置位置动画,可以传递一个包含3个位置(开始、中间、结束)的数组
如果执行此操作,您将注意到视图从起点直线移动到中点,从另一条直线移动到终点。通过中点使其从起点变为终点所缺少的部分是更改动画的计算模式
move.calculationMode = kCAAnimationCubic;
您可以通过更改张力值
、连续性值
和biasValues
属性来控制圆弧。如果您想要更好的控制,您可以定义自己的路径,而不是值
数组
要遵循的路径
您可以创建任何路径,并指定属性应遵循该路径。这里我使用一个简单的圆弧
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL,
startPoint.x, startPoint.y);
CGPathAddCurveToPoint(path, NULL,
controlPoint1.x, controlPoint1.y,
controlPoint2.x, controlPoint2.y,
endPoint.x, endPoint.y);
CAKeyframeAnimation *move = [CAKeyframeAnimation animationWithKeyPath:@"position"];
move.path = path;
move.duration = 2.0f;
myView.layer.position = endPoint; // instead of removeOnCompletion
[myView.layer addAnimation:move forKey:@"move the view"];
我来晚了,但又来了。我正在尝试做类似的事情。在我最近做的WP7(Silverlight)应用程序中设置它非常容易。只需分别设置X和Y的动画,就可以得到一个圆弧。可能是动画不支持单独的动画X和Y。@Jonny如果你觉得你的问题与此不同,那么你可以创建自己的问题,并解释为什么它与此不同。“需要”路径有点强。传递3个值和一个立方计算模式将得到相同的结果,在我看来更容易掌握。是的,对于简单的情况。我有点避免了立方模式,因为我无法可视化偏置/连续性/张力三要素,贝塞尔点方法更简单,因为我已经使用了大量的贝塞尔曲线向量程序,我对这些很熟悉。
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL,
startPoint.x, startPoint.y);
CGPathAddCurveToPoint(path, NULL,
controlPoint1.x, controlPoint1.y,
controlPoint2.x, controlPoint2.y,
endPoint.x, endPoint.y);
CAKeyframeAnimation *move = [CAKeyframeAnimation animationWithKeyPath:@"position"];
move.path = path;
move.duration = 2.0f;
myView.layer.position = endPoint; // instead of removeOnCompletion
[myView.layer addAnimation:move forKey:@"move the view"];