gpt4 book ai didi

ios - 使用 kCAMediaTimingFunctionEaseIn 有问题吗?

转载 作者:可可西里 更新时间:2023-11-01 04:51:46 27 4
gpt4 key购买 nike

我正在使用 CALayerCAReplicatorLayerCABasicAnimation 将条形图设置为动画。条形图由“段”组成,我用 CALayer 将其呈现为小矩形。然后我将它们作为子层添加到循环中的 CAReplicatorLayer 中。最后,我为每个小矩形添加一个动画,将矩形放入图表中的位置。

这是动画的最终状态:

Correct final state of the animation

这是动画中间的样子:

Animating state

这是实现它的代码:

#define BLOCK_HEIGHT 6.0f
#define BLOCK_WIDTH 8.0f

@interface TCViewController ()

@property (nonatomic, strong) NSMutableArray * blockLayers; // blocks that fall from the sky
@property (nonatomic, strong) NSMutableArray * replicatorLayers; // replicator layers that will replicate the blocks into position

@end

@implementation TCViewController

- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];

self.blockLayers = [NSMutableArray array];
self.replicatorLayers = [NSMutableArray array];

NSArray * dataBlocksData = @[@1,@2,@3,@1,@5,@2,@11,@14,@5,@12,@10,@3,@7,@6,@3,@4,@1];

__block CGFloat currentXPosition = 0.0f;

[dataBlocksData enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) {

currentXPosition += BLOCK_WIDTH + 2.0f;

if (obj.integerValue == 0) return;

// replicator layer for data blocks in a column
CAReplicatorLayer * replicatorLayer = [[CAReplicatorLayer alloc] init];
replicatorLayer.frame = CGRectMake(currentXPosition, 0.0f, BLOCK_WIDTH, 200.0f);

// single data block layer (must be new for each replicator layer. can't reuse existing layer)
CALayer * blockLayer = [[CALayer alloc] init];
blockLayer.frame = CGRectMake(0, 200-BLOCK_HEIGHT, BLOCK_WIDTH, BLOCK_HEIGHT);
blockLayer.backgroundColor = [UIColor whiteColor].CGColor;
[replicatorLayer addSublayer:blockLayer];

replicatorLayer.instanceCount = obj.integerValue;
replicatorLayer.instanceDelay = 0.1f;
replicatorLayer.instanceTransform = CATransform3DMakeTranslation(0, -BLOCK_HEIGHT, 0); // negative height moves back up the column

[self.blockLayers addObject:blockLayer];
[self.replicatorLayers addObject:replicatorLayer];
}];
}

- (void)viewDidLayoutSubviews {
// add replicator layers as sublayers
[self.replicatorLayers enumerateObjectsUsingBlock:^(CAReplicatorLayer * obj, NSUInteger idx, BOOL *stop) {
[self.view.layer addSublayer:obj];
}];
}

- (void)viewDidAppear:(BOOL)animated {

// add animations to each block layer
[self.blockLayers enumerateObjectsUsingBlock:^(CALayer * obj, NSUInteger idx, BOOL *stop) {
// position animation
CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
animation.fromValue = @(-300);
animation.toValue = @(0);
animation.duration = 1.0f;
animation.fillMode = kCAFillModeBoth;
animation.removedOnCompletion = NO;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
[obj addAnimation:animation forKey:@"falling-block-animation"];
}];
}

最后,这里是问题所在。如果您未指定 timingFunctionLinear 函数或 EaseIn 函数,则动画不会完全完成。就像积木没有完全落到位一样。看起来他们快要完成了,但还不完全是。只差一两帧。换掉 -viewDidAppear: 中的计时函数赋值:

enter image description here

来吧,试试吧。我什至尝试指定一个带有控制点 ( link ) 的函数,它与 EaseIn 函数完全一样:

// use control points for an EaseIn timing:
animation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.42 :0.00 :1.0 :1.0];

// or simply specify the ease in timing function:
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

出于某种原因,EaseOutDefault 计时函数工作正常,但在视觉上,ease in style 函数似乎需要更长的时间才能完成,这可能是因为曲线的长度插值?

我已经尝试了很多方法来缩小问题的范围:

  1. 不在这些结构上循环,只使用 1 个图层和 1 个复制器图层制作相同的动画。我的意思是,只为一列制作动画。没运气。循环不是问题。
  2. 将创建、添加子层和添加动画的代码都放在-viewDidAppear中。如果在 View 的生命周期中更早或更晚添加动画,似乎没有什么不同。
  3. 为我的结构使用属性。没有区别。
  4. 没有为我的结构使用属性。同样,没有区别。
  5. 添加了动画完成回调以移除动画,从而使列处于正确的“最终”状态。这不是很好,但值得一试。
  6. 此问题在 iOS 6 和 7 中均存在。

我真的很想使用 EaseIn 计时功能,因为它是物体落入到位的最佳动画。我还想使用 CAReplicatorLayer,因为它完全符合我的要求。

那么我使用的 EaseIn 计时函数有什么问题呢?这是错误吗?

最佳答案

我同意这似乎是 CAReplicatorLayer 和 kCAMediaTimingFunctionEaseIn 计时函数组合中的错误。

作为解决方法,我建议使用具有三个关键帧的关键帧动画。前两个关键帧使用缓入时间定义您想要的动画。最后一个关键帧被定义为与第二个关键帧相同,但让动画有更多时间停留在最终关键帧上,这似乎让复制器层将最后一个复制层动画化为最终状态。

因此我的建议是:

CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.y"];

// extra keyframe duplicating final state
animation.values = @[@-300.0f, @0.0f, @0.0f];

// double length of original animation, with last half containing no actual animation
animation.keyTimes = @[@0.0, @0.5, @1.0];
animation.duration = 2.0f;

animation.fillMode = kCAFillModeBoth;
animation.removedOnCompletion = NO;

// ease-in for first half of animation; default after
animation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
[obj addAnimation:animation forKey:@"falling-block-animation"];

关于ios - 使用 kCAMediaTimingFunctionEaseIn 有问题吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24413183/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com