折叠动画没有与滑动动画对齐

时间:2012-10-03 10:33:21

标签: objective-c ios core-animation

我正在尝试创建像这样的折叠菜单动画:http://vimeo.com/41495357

此时动画在屏幕上拖动时会起作用,但是当我尝试将菜单从打开设置为关闭或关闭以直接打开时,滑动的主视图不会与右侧对齐正在展开的观点。它们在动画结束时对齐,但在动画期间不对齐。此外,正在展开的视图边缘似乎在动画期间消失在视图边界之外。

图层的实际展开是在layoutSublayers中完成的,因此当图层的宽度发生变化时,会计算其子图层上的变换。我找到了计算此项目中变换的数学运算:https://github.com/MassiveHealth/Opaque

// Configure the layer bounds and midpoints
CGRect halfRect = CGRectMake(0, 0, self.fullWidth / 2, self.bounds.size.height);
self.rightImageLayer.bounds = halfRect;
self.leftImageLayer.bounds = halfRect;
CGPoint midPoint = CGPointMake(0.5 * self.bounds.size.width, 0.5 * self.bounds.size.height);
self.rightImageLayer.position = midPoint;
self.leftImageLayer.position = midPoint;

// Calculate transforms
CGFloat l = 0.5 * self.fullWidth;
CGFloat y = 0.5 * self.bounds.size.width;
CGFloat theta = acosf(y/l);
CGFloat z = l * sinf(theta);
CGFloat topAngle = theta * -1;
CGFloat bottomAngle = theta;

CATransform3D transform = CATransform3DMakeTranslation(0.0, 0.0, -z);
self.rightImageLayer.transform = CATransform3DRotate(transform, topAngle, 0.0, 1.0, 0.0);
self.leftImageLayer.transform = CATransform3DRotate(transform, bottomAngle, 0.0, 1.0, 0.0);

这是负责启动展开动画的代码。 (现在菜单展开到屏幕的整个宽度)

self.foldingLayer.frame = self.view.bounds;
self.slidingLayer.frame = CGRectMake(self.view.frame.size.width, 0, self.slidingLayer.frame.size.width, self.slidingLayer.frame.size.height);

为什么这些动画不排队?也许数学不正确?我查看了https://github.com/honcheng/PaperFold-for-iOShttps://github.com/xyfeng/XYOrigami等项目的示例代码,但我无法弄明白。

更新

根据Till的回答,我为滑动层创建了这个关键帧动画。动画仍然没有对齐,所以我的关键帧计算必定是错误的?

CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position.x"];

NSUInteger steps = 100;
CGFloat totalFoldViewWidth = self.view.bounds.size.width;
NSMutableArray *values = [NSMutableArray arrayWithCapacity:steps];

for(NSUInteger i = 0; i < steps; i++) {
    CGFloat fraction = (CGFloat)i / steps;
    CGFloat foldViewWidth = fraction * totalFoldViewWidth;
    CGFloat l = 0.5 * totalFoldViewWidth;
    CGFloat y = 0.5 * foldViewWidth;
    CGFloat angle = acosf(y/l);
    CGFloat projectionWidth = cosf(angle) * totalFoldViewWidth;
    [values addObject:[NSNumber numberWithFloat:projectionWidth]];
}
animation.calculationMode = kCAAnimationLinear;
[animation setValues:values];
[animation setDuration:3.0];

[self.slidingLayer addAnimation:animation forKey:@"slideAnimation"];

2 个答案:

答案 0 :(得分:3)

我认为你是从错误的方向解决问题。您想要从距离计算角度,反之亦然。如果要计算折叠动画每一侧的角度,可以使用基本的毕达哥拉斯算法。很明显,我们知道开口距离的大小,我们知道斜边的大小(完全打开时视图大小的一半)。

在代码中:

CGFloat otherSide = 0.5 * openingWidth; // halve because we have two sides
CGFloat hypotenuse = 0.5 * unfoldedViewTotalWidth; // halve because we have to sides
CGFloat angle = asinf(otherSide / hypotenuse);
CGFloat rightAngle = -1 * (M_PI_2 - angle);
CGFloat leftAngle = M_PI_2 - angle;

您可以使用这些角度设置折叠视图左侧和右侧的旋转。

请注意将左侧的锚点设置为(0.0,0,5),将右侧的锚点设置为(1.0,0.5),并为右侧翻译设置动画!

希望这有帮助!干杯!

答案 1 :(得分:0)

这确实是你数学的问题。该视图的距离取决于折叠视图的投影宽度。根据角度,该宽度不是严格线性的;

projectionWidth = cos(angle) * foldViewWidth

换句话说,40度会产生完全不同于20度的东西,并且这种关系不是线性的,而是基于该角度的余弦。

因此,线性动画不会这样做。您需要根据折叠视图的投影宽度创建一个帧动画,以使平移与旋转相匹配。