Objective c 在NSOutlineView中承载NSView的层
我正在尝试创建一个自定义的Objective c 在NSOutlineView中承载NSView的层,objective-c,macos,cocoa,calayer,nsoutlineview,Objective C,Macos,Cocoa,Calayer,Nsoutlineview,我正在尝试创建一个自定义的NSView,它承载一个CALayer层次结构,以执行有效的显示。然后,此NSView被嵌入到基于视图的NSOutlineView显示的NSTableCellView中 问题是,每当我展开或折叠一个项目时,所有行都会被移动,但图层的内容仍显示在更改轮廓之前的位置 滚动NSOutlineView似乎会刷新图层,此时图层与行重新同步 我已经用仪器调试过这种行为,滚动似乎引发了一个布局操作,该操作使用setPosition:调用更新图层,该调用应该在展开或折叠项目时发生 下面
NSView
,它承载一个CALayer
层次结构,以执行有效的显示。然后,此NSView
被嵌入到基于视图的NSOutlineView
显示的NSTableCellView
中
问题是,每当我展开或折叠一个项目时,所有行都会被移动,但图层的内容仍显示在更改轮廓之前的位置
滚动NSOutlineView
似乎会刷新图层,此时图层与行重新同步
我已经用仪器调试过这种行为,滚动似乎引发了一个布局操作,该操作使用setPosition:
调用更新图层,该调用应该在展开或折叠项目时发生
下面是托管NSView
子类的简单层的一些示例代码
@interface TestView : NSView
@end
@implementation TestView
- (instancetype)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
CAShapeLayer* layer = [CAShapeLayer layer];
layer.bounds = self.bounds;
layer.position = CGPointMake(NSMidX(self.bounds), NSMidY(self.bounds));
layer.path = [NSBezierPath bezierPathWithOvalInRect:self.bounds].CGPath;
layer.fillColor = [NSColor redColor].CGColor;
layer.delegate = self;
self.layer = layer;
self.wantsLayer = YES;
return self;
}
@end
我已经尝试了很多解决这个问题的潜在方法,但是我找不到任何在NSView
实例上调用的有趣方法,这些方法可以被覆盖以调用[self.layer setNeedsDisplay]
或[self.layer setNeedsLayout]
。我还尝试了CALayer
本身的各种设置,例如:
layer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
layer.needsDisplayOnBoundsChange = YES;
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
有谁能帮我弄清楚如何在
NSOutlineView
中正确显示此层吗?阅读NSOutlineView
参考文档并找到可能让您适合这里的有关单元重用的信息是很困难的
您可能已经看过了outlineViewItemDidCollapse:
,但对于我们的问题来说,它是一个无用的工具,因为它没有指向NSView
的指针,这是因为它比基于视图的大纲视图旧
在outlineView:didRemoveOWView:forRow:
中关于基于视图的NSOutlineView方法的部分中,可能有一个有用的提及,隐藏在NSOutlineView:forRow:
协议中:
删除的行视图可能会被表重用,因此此时应删除任何额外插入的视图
换句话说,当您调用outline视图的makeViewWithIdentifier:owner:
时,对于具有特定ID的cellView或rowView,您通常会得到一个循环视图。尤其是因为坍塌。顺便说一句,该方法来自NSTableView
超类,在该引用中,还有:
此方法还可能返回一个重用视图,该视图具有屏幕上不再可用的相同标识符。如果无法从nib文件实例化具有指定标识符的视图,或者无法在重用队列中找到该视图,则此方法返回nil
因此,您可以在didRemoveRowView:forRow
中选择更改视图层次结构或niling属性。但是,在第三个cocoa参考中,即对于NSView
,在prepareforeuse
的注释中
此方法提供了一种将视图重置为某些初始状态的方法,以便可以重用该视图。例如,NSTableView类使用它来准备视图以供重用,从而避免在视图滚动到视图中时创建新视图的开销。如果您在自己的代码中实现了视图重用系统,则可以在重用它们之前从自己的代码中调用此方法
因此,TL;DR,您需要实施prepareforeuse
相关参考(主要)是NSOutlineView
和NSTableCellView
的超类
而且,FWIW,有一个问题,提问者似乎指出事情比我想象的更糟,因为NSOutlineView在幕后比NSTableView更具创造性
在我自己使用outline视图和嵌入式NSTextView的工作中,我看到了与展开/折叠/滚动相关的非常糟糕的渲染问题,我似乎只在NSOutlineViewDeleteGate方法中处理了这些问题。在iOS上,他们帮了大家的忙,将
makeViewWithIdentifier
重命名为更明确的dequeueReusableCellViewWithIdentifier
,最后我回答了我的问题。问题不在于我的TestView的实现方式。我只是错过了在应用程序中启用CoreAnimation支持的一个步骤。相关参考在核心动画编程指南中
基本上,在iOS内核中,默认情况下始终启用动画和层备份。在OS X上,必须通过以下方式启用:
- 在nib文件中,使用视图效果检查器为视图启用图层支持。检查器将显示选定视图及其子视图的复选框。建议尽可能在窗口的内容视图中启用层支持
- 对于以编程方式创建的视图,请调用视图的setWantLayer:方法,并传递值YES以指示视图应使用层
一旦我在NSOutlineView的任何父视图上启用了层支持,各种小故障就解决了。您不必为任何祖先视图(如大纲视图)启用层备份 根据我的经验,立即指定给视图的层(与子层相反)不需要设置其边界、位置或自动调整大小的遮罩。将自动使其跟踪视图的边界。事实上,我会避免设置这些属性,以防破坏与视图的bounds rect的自动同步 因此,问题是:您如何安排视图随其superview移动或调整大小?你在使用自动布局吗?如果是,您是否关闭了其
翻译自动调整大小GMaskintoConstraints
?如果两者均为“是”,则在视图上设置哪些约束?如果其中一个都没有,您是如何定位视图w的