首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >这种kCAMediaTimingFunctionEaseIn的使用有问题吗?

这种kCAMediaTimingFunctionEaseIn的使用有问题吗?
EN

Stack Overflow用户
提问于 2014-06-25 15:46:35
回答 1查看 406关注 0票数 5

我使用CALayerCAReplicatorLayerCABasicAnimation来绘制条形图。条形图由向上的“段”组成,我用CALayer渲染成小矩形。然后我将它们作为子层添加到循环中的CAReplicatorLayer中。最后,我为每个小矩形添加一个动画,将矩形放到图表中的位置。

以下是动画的最终状态:

下面是动画中间的样子:

下面是实现这一目标的代码:

代码语言:javascript
复制
#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:中的定时函数分配,您就会得到这种奇怪的结果:

去吧,试试吧。我甚至尝试使用完全类似于链接函数的控制点( EaseIn )指定一个函数:

代码语言:javascript
复制
// 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定时函数工作得很好,但是风格上的函数似乎需要更长的时间才能完成,视觉上来说,这可能是因为插值曲线的长度?

我已经尝试了很多事情来缩小这个问题:

  1. 不要在这些结构上循环使用相同动画的1层和1层复制器层。我的意思是,只动了一列。不走运。循环不是问题。
  2. 将创建、子层添加和动画添加代码全部放在-viewDidAppear中。如果动画是在视图生命周期的早期或后期添加的话,似乎没有什么区别。
  3. 为我的结构使用属性。没什么区别。
  4. 不为我的结构使用属性。再说一遍,没什么区别。
  5. 为动画完成添加回调以删除动画,从而使列保持正确的“最终”状态。这不太好,但值得一试。
  6. 这个问题在iOS 6和7中都存在。

我真的很想使用EaseIn的计时功能,因为它是最好看的动画。我还想使用CAReplicatorLayer,因为它做的正是我想做的事情。

那么,当我使用EaseIn定时函数时,它们有什么问题呢?这是个虫子吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-06-25 18:58:34

我同意这似乎是CAReplicatorLayer和kCAMediaTimingFunctionEaseIn定时函数组合中的一个缺陷。

作为解决办法,我建议使用带有三个关键帧的关键帧动画。前两个关键帧定义了您想要的动画与轻松的时间。最后一个关键帧被定义为与第二个关键帧相同,但是给动画额外的时间坐在最后的关键帧上,这似乎让复制者层将最后复制的层动画到最后的状态。

因此,我的建议是:

代码语言:javascript
复制
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"];
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24413183

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档