4

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

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

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

// 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"];
4

2 回答 2

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),并为右侧的平移设置动画!

希望这可以帮助!干杯!

于 2012-10-05T16:01:53.653 回答
0

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

projectionWidth = cos(angle) * foldViewWidth

换句话说,40 度的结果与 20 度完全不同,这种关系不是线性的,而是基于该角度的余弦。

因此线性动画是行不通的。您需要根据折叠视图的投影宽度创建帧动画,以匹配平移和旋转。

于 2012-10-03T11:19:11.740 回答