CALayer 实时调整大小性能不佳
我有一个 UI,其中 NSCollectionViewItem 的视图内容是通过 CALayers 以编程方式绘制的。我使用 CAConstraintLayoutManager 来在调整大小时保持子层的布局一致,但这样做时性能非常差。看起来,调整窗口大小会导致调整两个 CATextLayer 的大小,以便它们适合根层的宽度,并重新定位一个 CATextLayer 使其保持正确位置 -对齐,导致应用程序花费大部分时间执行 CGSScanConvolveAndIntegrateRGB 函数(我使用了 Time Profiler 工具)。
最“昂贵”的层(即使是唯一显示的层,也会导致最卡顿的层)是包装的多行CATextLayer
。我完全不知道如何获得更好的性能(我尝试过不使用 CAConstraintLayoutManager 并使用图层对齐,但我得到了同样的结果)。有人遇到过这个问题吗?有办法解决吗?
PS:我已经对布局管理器进行了子类化,并通过在 - (void)layoutSublayersOfLayer:(CALayer *)layer
执行期间将 YES 设置为 kCATransactionDisableActions
禁用了所有动画code>CATransaction 但它似乎没有帮助。
编辑:我已经禁用了文本层的字体平滑,并且性能提高了一点(非常少),但它在 _ZL9view_drawP7_CAViewdPK11CVTimeStampb 中花费了大量时间(这是由线程调用的)我想是 ATI Radeon 驱动程序的一部分)。
I have a UI where the content of an NSCollectionViewItem
's View is drawn programmatically through CALayers. I am using a CAConstraintLayoutManager
to keep the layot of the sublayers consistent when resizing, but I am getting very poor performance when doing so. It seems that resizing the window, which causes the resize of two CATextLayer
s so that they fit the root layer's width, and the repositioning of one CATextLayer
so that it stays right-aligned, is causing the application to spend most of its time executing the CGSScanConvolveAndIntegrateRGB
function (I have used the Time Profiler instrument).
The most "expensive" layer (the one that causes the most stuttering even if it's the only one displayed) is a wrapped multiline CATextLayer
. I have absolutely no idea how to get better performance (I have tried not using a CAConstraintLayoutManager
and going with layer alignments but I'm getting the same thing). Has anyone had this problem? Is there a way around it?
PS: I have subclassed the layout manager and disabled all the animations during the execution of - (void)layoutSublayersOfLayer:(CALayer *)layer
by setting YES to kCATransactionDisableActions
in the CATransaction
but it doesn't seems to help.
Edit: I have disabled Font Smoothing for the Text Layers and performance has increased a little bit (very little), but it spends an awful amount of time in _ZL9view_drawP7_CAViewdPK11CVTimeStampb (which is something that gets called by a thread of the ATI Radeon driver, I suppose).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我解决了。有点儿。对我来说,这仍然像是一个肮脏的黑客行为,但我无法找到如何使
setNeedsDisplayInRect
工作,所以我最终这样做了:在 NSWindow 委托中:
-(void)windowWillStartLiveResize:(NSNotification *)通知
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"beginResize" 对象:nil];
}
-(void)windowDidEndLiveResize:(NSNotification *)通知
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"endResize" 对象:nil];
在NSWindow
-(void)beginResize
和-(void)endResize
选择器。第一个将 BOOL inLiveResize 变量设置为 YES,而第二个将其设置为 NO,并使用新的帧大小再次调用 setFrameSize。我重写了(重写?不是英语为母语,抱歉)
-(void)setFrameSize:(NSSize)newSize
方法,如下所示:就是这样。这样,只有可见视图随窗口实时调整大小,而其他视图则在操作结束时重新绘制。它可以工作,但我不喜欢它有多“脏”,我确信有一种更优雅的内置方法可以通过使用 setNeedsDisplayInRect 方法来实现此目的。我会进一步研究。
I solved it. Kind of. It still seems like a dirty hack to me, but I couldn't find out how to make
setNeedsDisplayInRect
work so I ended up doing it like this:In the NSWindow delegate:
-(void)windowWillStartLiveResize:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"beginResize" object:nil];
}
-(void)windowDidEndLiveResize:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"endResize" object:nil];
}
In my Custom View those two notifications call, respectively, the
-(void)beginResize
and-(void)endResize
selectors. The first one sets a BOOL inLiveResize variable to YES, while the second one sets it to NO and calls setFrameSize again with the new frame size.I overrode (overridden? Not native english speaker, sorry) the
-(void)setFrameSize:(NSSize)newSize
method like this:That's it. This way, only the visible views resize live with the window, while the others get redrawn at the end of the operation. It works, but I don't like how 'dirty' it is, I'm sure there is a more elegant, built-in(ish) way to do this by using the
setNeedsDisplayInRect
method. I will research more.