有没有一种正确的方法来处理重叠的NSView兄弟姐妹?

时间:2009-01-21 17:44:52

标签: cocoa

我正在研究一个Cocoa应用程序,我遇到了一个我希望两个NSView对象重叠的情况。我有一个父NSView,它包含两个子视图(NSView A和NSView B),每个子视图可以有几个自己的子视图。

有没有正确的方法来处理这种重叠? NSView B总是“在NSView A之上”,所以我希望屏蔽NSView A的重叠部分。

5 个答案:

答案 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调用,只有视图直接层次结构。

更新1

要解决这个问题,我必须深入挖掘,深入挖掘。可能是一周的研究,我已经将我的研究结果传播到几篇文章中。最后的突破是在本文中:http://eon.codes/blog/2015/12/24/The-odd-case-of-luck/

更新2

虽然这个概念很难理解,但是它很有效,但它很有效。以下是支持它的最终结果和代码,指向github repo等的链接:http://eon.codes/blog/2015/12/30/Graphic-framework-for-OSX/

相关问题