动画:性能调整
我的应用程序正在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
也需要先运行。 尝试分解你的任务,并设置分析代码来衡量time
和frequency
。 如果您可以测量每个任务使用多少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