【问题标题】:How do I make an NSView move to the front of all NSViews如何使 NSView 移动到所有 NSView 的前面
【发布时间】:2011-02-21 19:18:12
【问题描述】:

我有一个超级视图,它有 2 个子视图。 这些子视图是重叠的。

每当我从菜单中选择一个视图时,相应的视图应该成为前视图并处理操作。 即,它应该是最前面的子视图。

acceptsFirstResponder 辞职一切正常。 但是鼠标按下事件被发送到设置的最顶层子视图。

问候, 禅那

【问题讨论】:

  • 请注意:“注意:出于性能原因,Cocoa 不强制在同级视图之间进行剪辑……”此外! “当兄弟视图重叠时,Cocoa 不能保证正确的失效和绘制行为。”正如手册中所说:“如果您希望在另一个视图前面绘制一个视图,您应该使前视图成为后视图的子视图(或后代)。” (来自 OSX doco 中的 View Programming Guide)

标签: cocoa nsview


【解决方案1】:

这是另一种更清晰简洁的方法:

[viewToBeMadeForemost removeFromSuperview];
[self addSubview:viewToBeMadeForemost positioned:NSWindowAbove relativeTo:nil];

根据此方法的文档,当您使用 relativeTo:nil 时,视图会添加到其所有同级的上方(或下方,使用 NSWindowBelow)。

【讨论】:

  • 上述方法有问题。首先,当您将 removeFromSuperview 发送到视图时,它会被释放。因此,您首先需要保留视图,然后再平衡原始保留与释放。其次,您需要将视图删除和添加到层次结构的开销(这可能会很昂贵,具体取决于视图层次结构的复杂性)。还有另一种方法可以避免使用 NSView 的内置子视图排序功能从视图层次结构中删除和添加视图。见下文。
  • 我觉得这两行代码还在同一个事件循环中,所以viewToBeMadeForemost不会在第二行之前发布。
  • @LiFumin,这是不正确的。您假设 removeFromSuperview 自动释放视图,或者其他代码自动释放它。来自 -removeFromSuperview 的文档:“视图也已发布;如果您打算重用它,请务必在发送此消息之前保留它,并在将其添加为另一个 NSView 的子视图时酌情释放它。”达尔马齐奥是正确的,观点必须保留。我想这个解决方案也有关于打破约束等的问题。它不应该是公认的答案。
  • 另一个问题:从超级视图释放约束中删除
  • 如果您删除作为第一响应者的视图,它将失去焦点。
【解决方案2】:

另一种方法是使用 NSView 的 sortSubviewsUsingFunction:context: 方法根据您的喜好重新排序同级视图的集合。例如,定义您的比较函数:

static NSComparisonResult myCustomViewAboveSiblingViewsComparator( NSView * view1, NSView * view2, void * context )
{    
    if ([view1 isKindOfClass:[MyCustomView class]])    
        return NSOrderedDescending;    
    else if ([view2 isKindOfClass:[MyCustomView class]])    
        return NSOrderedAscending;    

    return NSOrderedSame;
}

然后,当您想确保您的自定义视图保持在所有同级视图之上时,请将此消息发送到您的自定义视图的超级视图:

[[myCustomView superview] sortSubviewsUsingFunction:myCustomViewAboveSiblingViewsComparator context:NULL];

或者,您可以将此代码移动到超级视图本身,并将消息 sortSubviewsUsingFunction:context: 发送给 self

【讨论】:

  • @Jonathan。这适用于作为 iOS 框架一部分的 UIView。问题是关于用于 OS X 应用程序的 NSViews。
  • 这可行,但似乎使其余子视图的顺序随机化,因为文档说“如果它们的顺序不重要,则为 NSOrderedSame”。保留其余视图顺序的解决方案会好得多。另外,IsKindOfClass: 的使用很奇怪;该问题并未说明正在使用自定义视图子类,或者要重新排序的同级子视图是不同的类。
【解决方案3】:

在模仿等效 UIView 方法的 Swift 4 类别中使用@Dalmazio 的答案给出以下结果:

extension NSView {

    func bringSubviewToFront(_ view: NSView) {
            var theView = view
            self.sortSubviews({(viewA,viewB,rawPointer) in
                let view = rawPointer?.load(as: NSView.self)

                switch view {
                case viewA:
                    return ComparisonResult.orderedDescending
                case viewB:
                    return ComparisonResult.orderedAscending
                default:
                    return ComparisonResult.orderedSame
                }
            }, context: &theView)
    }

}

所以,把subView 带到containerView 的前面

containerView.bringSubviewToFront(subView)

与删除和重新添加视图的解决方案不同,这使约束保持不变

【讨论】:

    【解决方案4】:

    我能够在不调用 removeFromSuperView 的情况下让它工作

    // pop to top
    [self addSubview:viewToBeMadeForemost positioned:NSWindowAbove relativeTo:nil];
    

    【讨论】:

    • 这会创建一个新视图而不是使用现有视图吗?
    • 这导致应用程序永远挂起。
    • 如果这行得通,那只是偶然;文档不保证添加已添加视图的行为。
    【解决方案5】:

    下面给出的代码应该可以正常工作..

        NSMutableArray *subvies = [NSMutableArray arrayWithArray:[self subviews]];//Get all subviews..
    
        [viewToBeMadeForemost retain]; //Retain the view to be made top view..
    
        [subvies removeObject:viewToBeMadeForemost];//remove it from array
    
        [subvies addObject:viewToBeMadeForemost];//add as last item
    
        [self setSubviews:subvies];//set the new array..
    

    【讨论】:

    • 这应该是公认的答案,因为它比其他答案更接近正确。但是,请注意,它应该执行 [viewToBeMadeForemost 发布];最后,否则有泄漏。
    【解决方案6】:

    您只需再次添加视图即可实现此目的;它不会创建它的另一个实例。

    [self addSubview:viewToBeMadeForemost];
    

    可以记录这行代码执行前后的子视图数量。

    【讨论】:

    • 如果这行得通,那只是偶然;文档不保证添加已添加视图的行为。
    【解决方案7】:

    你可以试试这个:

    [viewToBeMadeFirst.window makeKeyAndOrderFront:nil];
    

    【讨论】:

    • 是的,这个对我有用:[self.window makeKeyAndOrderFront:self];
    • 我们说的是 NSView,而不是 NSWindow
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-08
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 2012-07-01
    • 2015-09-06
    • 1970-01-01
    相关资源
    最近更新 更多