我正在研究一个Cocoa应用程序,我遇到了一个我希望两个NSView对象重叠的情况。我有一个父NSView,它包含两个子视图(NSView A和NSView B),每个子视图可以有几个自己的子视图。
有没有正确的方法来处理这种重叠? NSView B总是“在NSView A之上”,所以我希望屏蔽NSView A的重叠部分。
答案 0 :(得分:13)
Chris,唯一的解决方案就是使用CALayers。这绝对是唯一的解决方案。
NSX在OSX(2010年9月)中很明显:兄弟姐妹无法正常工作。其中一个会随机出现在最上面。
重复一遍,问题出在兄弟姐妹。
要测试这个:使用NSViews和/或nsimageviews。制作一个视图是一个大图像的应用程序(1000x1000说)。在视图中,在这里和那里放置三个或四个小图像/ NSView。现在将另一个大的1000x1000图像放在上面。反复构建和启动应用程序 - 你会发现它很明显。通常,下面(小)层将出现在大覆盖层的顶部。如果你打开NSViews上的图层支持,无论你尝试什么组合,它都无济于事。所以这是最终的测试。
您必须放弃NSView并使用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];
然后,一切都完美无缺,你可以对任何你想要的东西进行嵌套和分组,无论你的结构多么复杂,它都可以完美无缺地显示在上/下应该出现在上面/下面的所有东西上面。之后你可以对这些图层做任何事情,或者以典型的方式改变周围的事物,
-(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];
}
(对于你所做的一切,令人讨厌的'零秒'封装器的唯一原因是为了防止免费提供给你的动画 - 除非你想要动画!)
顺便提一下Apple的这句话,
出于性能原因,Cocoa确实如此 不强制兄弟之间的剪辑 观点或保证正确 失效和绘图行为时 兄弟视图重叠。
他们的以下句子......
如果要绘制视图 在另一个观点的前面,你应该做 前视图是子视图(或 后视图的后代。
在很大程度上是荒谬的(你不一定能用替代品代替兄弟姐妹;上面测试中描述的明显错误仍然存在)。
所以这是CALayers!享受!
答案 1 :(得分:6)
如果您的应用程序仅限10.5,请打开视图的图层,它应该可以正常工作。
如果你的意思是支持10.4及以下版本,你需要找到一种不让视图重叠的方法,因为重叠的兄弟视图是未定义的行为。正如View编程指南所说:
出于性能原因,Cocoa不会在兄弟视图之间强制执行剪切,或者在兄弟视图重叠时保证正确的失效和绘制行为。如果要在另一个视图前绘制视图,则应将前视图设为后视图的子视图(或后代)。
我见过一些可以让它有时候工作的黑客,但这不是你可以依赖的任何东西。您需要使View A成为View B的子视图,或制作一个处理其职责的巨型视图。
答案 2 :(得分:3)
有一种方法可以在不使用CALayers
的情况下完成,我正在研究的应用程序可以证明这一点。创建两个窗口并使用它:
[mainWindow addChildWindow:otherWindow ordered:NSWindowAbove];
要删除“ otherWindow ”,请使用:
[mainWindow removeChildWindow:otherWindow];
[otherWindow orderOut:nil];
你可能想要使用窗口的标题栏:
[otherWindow setStyleMask:NSBorderlessWindowMask];
答案 3 :(得分:1)
为了确保NSView B
始终与NSView A
重叠,请确保在添加NSWindowOrderingMode
subview:
[parentView addSubview:B positioned:NSWindowAbove relativeTo:A];
您还应该记住,如果视图B是100%不透明的,则不会要求A的隐藏部分重绘。
如果您要移动子视图,还需要确保拨打电话
-setNeedsDisplayInRect:
代表您正在发现的视图区域。
答案 4 :(得分:1)
正如Nate所写,人们可以使用:
self.addSubview(btn2, positioned: NSWindowOrderingMode.Above, relativeTo: btn1)
但是,只要您要求其中一个视图通过" needDisplay = true"重新绘制自己的视图,就不会遵守视图的顺序。调用
兄弟姐妹不会得到drawRect调用,只有视图直接层次结构。
要解决这个问题,我必须深入挖掘,深入挖掘。可能是一周的研究,我已经将我的研究结果传播到几篇文章中。最后的突破是在本文中:http://eon.codes/blog/2015/12/24/The-odd-case-of-luck/
虽然这个概念很难理解,但是它很有效,但它很有效。以下是支持它的最终结果和代码,指向github repo等的链接:http://eon.codes/blog/2015/12/30/Graphic-framework-for-OSX/