动画:性能调整

我的应用程序正在iPad上运行。 但表现非常糟糕 - 我低于15fps。 任何人都可以帮助我优化?

它基本上是一个包含12个按钮(从UIControl派生)的轮子(派生自UIView)。 控制的形象

当用户旋转它时,按钮会动态扩展和收缩(例如,12点钟位置的那个应该始终是最大的)

所以我的车轮包含一个:

- (void) displayLinkIsCallingBack: (CADisplayLink *) dispLink 
{
    :
    // using CATransaction like this goes from 14fps to 19fps
    [CATransaction begin];
    [CATransaction setDisableActions: YES];

    // NEG, as coord system is flipped/fucked
    self.transform = CGAffineTransformMakeRotation(-thetaWheel);

    [CATransaction commit];

    if (BLA)
        [self rotateNotch: direction];  
}

...根据最近的触摸输入计算轮子的新旋转。 这里已经有一个性能问题,我正在寻找一个单独的线程:iOS Core-Animation:CATransaction / Interpolating变换矩阵的性能问题

该程序还检查车轮是否已经完成另一次1/12转,如果是,则指示所有12个按钮调整大小:

// Wheel.m
- (void) rotateNotch: (int) direction
{
    for (int i=0; i < [self buttonCount] ; i++)
    {
            CustomButton * b = (CustomButton *) [self.buttons objectAtIndex: i];

    // Note that b.btnSize is a dynamic property which will calculate
    // the desired button size based on the button index and the wheels rotation.
            [b resize: b.btnSize];
    }
}

现在对于实际的调整大小代码,在button.m中:

// Button.m

- (void) scaleFrom: (float) s_old
                to: (float) s_new
              time: (float) t
{
    CABasicAnimation * scaleAnimation = [CABasicAnimation animationWithKeyPath: @"transform.scale"];

    [scaleAnimation setDuration:  t ];
    [scaleAnimation setFromValue:  (id) [NSNumber numberWithDouble: s_old] ];
    [scaleAnimation setToValue:  (id) [NSNumber numberWithDouble: s_new] ];
    [scaleAnimation setTimingFunction:  [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseOut] ];
    [scaleAnimation setFillMode: kCAFillModeForwards];
    scaleAnimation.removedOnCompletion = NO;

    [self.contentsLayer addAnimation: scaleAnimation 
                              forKey: @"transform.scale"];

    if (self.displayShadow && self.shadowLayer)
        [self.shadowLayer addAnimation: scaleAnimation 
                                forKey: @"transform.scale"];    

    size = s_new;
}

// - - - 

- (void) resize: (float) newSize
{
    [self scaleFrom: size
                 to: newSize
               time: 1.];
}

我不知道这个问题是否与多个transform.scale操作排队的开销有关 - 每个按钮的调整大小都需要一秒钟才能完成,如果我快速旋转轮子,我可能会每秒旋转几圈; 这意味着每个按钮的大小每秒调整24次。

**创建按钮的图层**

我猜的最后一块难题是看看按钮的内容层。 但我已经尝试过了

contentsLayer.setRasterize = YES;

应该将其有效存储为位图。 所以通过设置代码实际上动态调整了12位图的大小。

我无法相信这是在超出限制的范围内对设备征税。 然而,核心动画工具告诉我,否则; 当我旋转轮子(通过拖动我的手指圈),它报告〜15fps。

这并不好:我最终需要在每个按钮中放置一个文本图层,这会进一步降低性能(除非我使用上面的.setRasterize设置,在这种情况下它应该是相同的)。

必须有一些我做错了! 但是什么?

编辑:这里是负责生成按钮内容层的代码(即带阴影的形状):

- (CALayer *) makeContentsLayer
{
    CAShapeLayer * shapeOutline = [CAShapeLayer layer];
    shapeOutline.path = self.pOutline;

    CALayer * contents = [CALayer layer];

    // get the smallest rectangle centred on (0,0) that completely contains the button
    CGRect R = CGRectIntegral(CGPathGetPathBoundingBox(self.pOutline)); 
    float xMax = MAX(abs(R.origin.x), abs(R.origin.x+R.size.width));
    float yMax = MAX(abs(R.origin.y), abs(R.origin.y+R.size.height));
    CGRect S = CGRectMake(-xMax, -yMax, 2*xMax, 2*yMax);
    contents.bounds = S; 

    contents.shouldRasterize = YES; // try NO also

    switch (technique)
    {
        case kMethodMask:
            // clip contents layer by outline (outline centered on (0, 0))
            contents.backgroundColor = self.clr; 
            contents.mask = shapeOutline;
            break;

        case kMethodComposite:
            shapeOutline.fillColor = self.clr;
            [contents addSublayer: shapeOutline];
            self.shapeLayer = shapeOutline;
            break;

        default:
            break;
    }

    if (NO)
        [self markPosition: CGPointZero
                   onLayer: contents ];

    //[self refreshTextLayer];

    //[contents addSublayer: self.shapeLayerForText];

    return contents;
}

正如你所看到的,我正在尝试所有可能的方法,我正在尝试两种方法来制作形状,另外我正在切换.shouldRasterize

**妥协UI设计以获得可容忍的帧速率**

编辑:现在我已经尝试禁用动态调整大小的行为,直到车轮安定到一个新的位置,并设置wheel.setRasterize = YES。 所以它有效地旋转了手指下面的一个单独的预渲染的UIView(它被认为占据了大部分屏幕),直到轮子静止,此时它执行这个延迟调整大小的动画( @ <20FPS)。

虽然这给了一个可以容忍的结果,但我似乎很难以这种方式牺牲我的UI设计。 我确信我一定在做错事。

编辑:我刚刚尝试作为一个实验来手动调整按钮大小; 即在每个按钮中放置一个显示链接回调,并动态计算给定框架的预期大小,使用CATransaction显式禁用动画,就像我对轮子所做的一样,设置新的变换矩阵(从预期大小生成的比例变换)。 添加到此我已设置按钮内容层shouldRasterize = YES。 所以它应该简单地将每帧12个位图缩放到一个本身正在旋转的UIView上。 令人惊讶的是,这已经很慢了,它甚至会让模拟器停下来。 这绝对比使用核心动画的动画功能自动执行要慢10倍。


我没有开发iPad应用程序的经验,但我在优化视频游戏方面有一些经验。 所以,我不能给出确切的答案,但我想提供一些优化技巧。

不要猜测。 描述它。

看起来你正在试图在不分析代码的情况下进行更改。 改变一些可疑的代码并穿过你的手指并不实际。 你应该研究如何分析代码long每个任务需要,以及如何often也需要先运行。 尝试分解你的任务,并设置分析代码来衡量timefrequency 。 如果您可以测量每个任务使用多少memory或多少其他系统资源,则会更好。 根据证据找出你的瓶颈,而不是你的感觉。

对于您的具体问题,您认为在调整大小的工作开始时程序变得非常慢。但是,您确定吗? 它可能是别的。 我们不确定,直到我们有实际的分析数据。

最小化问题区域并在进行更改之前衡量实际性能。

分析后,你有一个候选人为你的瓶颈。 如果你仍然可以将事业分成几个小任务,那就去做一些分析,直到你不能再分裂为止。 然后,尝试通过反复运行它们几千次来测量它们的精确性能。 这很重要,因为在进行任何更改之前,您需要知道性能(速度和空间),以便将其与将来的更改进行比较。

对于您的具体问题,如果调整大小真的是问题,请尝试检查它的执行情况。 执行一次调整大小调用需要多长时间? 你需要多长时间调整一下工作来完成工作?

改进它。 怎么样? 这取决于。

现在,您遇到了有问题的代码块和当前的性能。 你现在必须改进它。 怎么样? 那么,这真的取决于问题是什么。 你可以搜索better algorithms ,如果你可以延迟计算直到你真的需要执行,你可以做lazy fetching ,或者如果你频繁地执行相同的操作,你可以通过缓存一些数据来进行over-eager evaluation 。 你越了解原因,你就越容易改善它。

对于你的具体问题,它可能只是OS UI功能的限制。 通常,调整大小按钮不仅仅是调整大小按钮本身,它也invalidates整个区域或其父部件invalidates以便每个用户的东西都可以正确呈现。 调整大小按钮可能很昂贵,如果是这种情况,只需使用基于图像的方法而不是基于OS ui的系统即可解决问题。 如果OS API的图像操作不够,可以尝试使用OpenGL。 但是,再次,我们不知道,直到我们实际尝试它们并且profile这些替代品。 祝你好运! :)


试试它没有你的阴影,看看是否提高性能。 我想它会大大改善它。 然后我会考虑使用CALayer的阴影路径来渲染阴影。 这将大大提高阴影渲染性能。

来自去年WWDC的苹果核心动画视频有很多关于核心动画性能提升的信息。

顺便说一下,我现在正在为一些更复杂的事情制作动画,即使是在较旧的iPhone 3G上,它也能很好地工作。 硬件/软件功能非常强大。


你应该在OpenGL中重新做这个

链接地址: http://www.djcxy.com/p/39485.html

上一篇: Animation: Performance tuning

下一篇: iPhone animation based on input values (touches) not time