有没有正确的方法来处理重叠的NSView兄弟姐妹?
我正在研究一个Cocoa应用程序,并且遇到了一个情况,我想让两个NSView对象重叠。 我有一个父级的NSView,其中包含两个子视图(NSView A和NSView B),其中每个子视图可以有自己的几个子视图。
有没有适当的方法来处理这种重叠? NSView B将永远是“上面”NSView A,所以我想NSView A的重叠部分被掩盖了。
如果你的应用程序只有10.5,打开图层的意见,它应该只是工作。
如果你的意思是支持10.4及以下版本,你需要find一种方法不要让视图重叠,因为重叠的同级视图是未定义的行为。 正如视图编程指南所说:
出于性能方面的原因,Cocoa不会在同级视图之间强制裁剪,或者当同级视图重叠时保证正确的失效和绘制行为。 如果您希望在另一个视图的前面绘制视图,则应该使前视图成为后视图的子视图(或后代)。
我曾经看到过一些可以让它有时候有点作用的黑客,但这不是你可以依赖的任何东西。 你需要使View A成为View B的子视图,或者制作一个处理这两个职责的巨大视图。
克里斯,唯一的解决scheme是使用CALayers。 这绝对是唯一的解决scheme。
NSX在OSX(2010年9月)中被打破: 兄弟姐妹无法正常工作。 一个或另一个将随机出现在顶部。
只要重复一遍,问题是与兄弟姐妹 。
要testing这个:使用NSViews和/或nsimageviews。 用一个大图像制作一个应用程序(1000×1000说)。 在视图中,放置三个或四个小图像/ NSViews在这里和那里。 现在把另一个大的1000×1000图像放在上面。 重复构build和启动应用程序 – 您会看到它被打破。 通常底层(小)层将出现在大覆盖层的顶部。 如果你在NSViews上打开层叠支持,不pipe你尝试什么组合,都没有帮助。 所以这是一个明确的testing。
你必须放弃NSViews并使用CALayers,就是这样。
与CALayers唯一的烦恼是,你不能用IB来设置你的东西。 你必须在代码中设置所有图层的位置,
yy = [CALayer layer]; yy.frame = CGRectMake(300,300, 300,300);
只能制作一个NSView,唯一的目的是保存你的第一个CALayer(也许称为“后部”),然后把所有的CALayer放在后面。
rear = [CALayer layer]; rear.backgroundColor = CGColorCreateGenericRGB( 0.75, 0.75, 0.75, 1.0 ); [yourOnlyNsView setLayer:rear]; // these two lines must be in this order [yourOnlyNsView setWantsLayer:YES]; // these two lines must be in this order [rear addSublayer:rr]; [rear addSublayer:yy]; [yy addSublayer:s1]; [yy addSublayer:s2]; [yy addSublayer:s3]; [yy addSublayer:s4]; [rear addSublayer:tt]; [rear addSublayer:ff];
所有的东西都完美地工作,你可以嵌套和分组任何你想要的东西,它完美地工作,一切正常地出现在上面/下面的所有东西上面/下面,不pipe你的结构多么复杂。 之后,你可以对图层做任何事情,或者以特殊的方式拖曳东西,
-(void) shuff { [CATransaction begin]; [CATransaction setValue:[NSNumber numberWithFloat:0.0f] forKey:kCATransactionAnimationDuration]; if .. [rear insertSublayer:ff below:yy]; else [rear insertSublayer:ff above:yy]; [CATransaction commit]; }
(对于你所做的一切而言,“零秒”包装器的恼人的唯一原因就是阻止免费赠送给你的animation – 除非你想要animation!)
顺便说一句,从苹果这个引用,
出于性能方面的原因,Cocoa不会在同级视图之间强制裁剪,或者当同级视图重叠时保证正确的失效和绘制行为。
他们下面的句子…
如果您希望在另一个视图前面绘制视图,则应该使前视图成为后视图的子视图(或后代)。
很大程度上是荒谬的(你不可能用subs替代兄弟,而上面testing中描述的明显的bug依然存在)。
所以这是CALayers! 请享用!
有没有办法做到这一点,而不使用CALayers
和我一直在努力的应用程序可以certificate这一点。 创build两个窗口并使用这个:
[mainWindow addChildWindow:otherWindow ordered:NSWindowAbove];
要删除“ otherWindow ”使用:
[mainWindow removeChildWindow:otherWindow]; [otherWindow orderOut:nil];
你可能会想要把窗口的标题栏带上:
[otherWindow setStyleMask:NSBorderlessWindowMask];
正如Nate所写,可以使用:
self.addSubview(btn2, positioned: NSWindowOrderingMode.Above, relativeTo: btn1)
然而,只要你通过“needDisplay = true”调用任意一个视图重新绘制视图,视图的sorting就不会被遵守
兄弟姐妹不会得到drawRect调用,只有视图直接层次结构会。
更新1
为了解决这个问题,我不得不深入深入地挖掘。 大概一个星期的研究和我的研究结果分散在一些文章。 最后的突破是在这篇文章: http : //stylekit.org/blog/2015/12/24/The-odd-case-of-luck/
更新2
虽然这个概念很难理解,但是它可以工作,而且效果很好。 这里是最终结果和代码来支持它,链接到github回购等: http : //stylekit.org/blog/2015/12/30/Graphic-framework-for-OSX/
为了确保NSView B
始终与NSView A
重叠,请确保在添加subview:
时使用正确的NSWindowOrderingMode
subview:
[parentView addSubview:B positioned:NSWindowAbove relativeTo:A];
您还应该记住,如果视图B是100%不透明的,A的隐藏部分将不会被要求重绘。
如果您要移动子视图,还需要确保您调用了-setNeedsDisplayInRect:
for您正在发现的视图区域。