Swift nspopover的设置位置

Swift nspopover的设置位置,swift,macos,nsviewcontroller,nspopover,Swift,Macos,Nsviewcontroller,Nspopover,我有一个视图控制器(a),它将另一个视图控制器(B)显示为popover 在我的VC(A)中,是一个带有此iAction的NSButton: self.presentViewController(vcPopover, asPopoverRelativeTo: myButton.bounds, of: myButton, preferredEdge: .maxX, behavior: .semitransient) 结果是: 现在我想改变我的府绸的位置-我想把它向上移动 我试过这个: let

我有一个视图控制器(a),它将另一个视图控制器(B)显示为popover

在我的VC(A)中,是一个带有此iAction的NSButton:

self.presentViewController(vcPopover, asPopoverRelativeTo: myButton.bounds, of: myButton, preferredEdge: .maxX, behavior: .semitransient)
结果是:

现在我想改变我的府绸的位置-我想把它向上移动

我试过这个:

let position = NSRect(origin: CGPoint(x: 100.0, y: 120.0), size: CGSize(width: 0.0, height: 0.0))
self.presentViewController(vcPopover, asPopoverRelativeTo: position, of: myButton, preferredEdge: .maxX, behavior: .semitransient)
但情况并没有改变

另一个例子


我有一个分段控制。如果您点击段“1”,将显示一个弹出框(与上面的代码相同)。但是箭头指向的是段“2”,而不是段“1”

首先,确保您的popover是真正的
NSPopover
,而不仅仅是
NSViewController
。假设要包装在popover中的视图控制器的故事板id为“vcPopover”,则获取内容vc如下所示:

let popoverContentController = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil).instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "vcPopover")) as! NSViewController
然后,将其包裹在一个popover中:

let popover = NSPopover()
popover.contentSize = NSSize(width: 200, height: 200) // Or whatever size you want, perhaps based on the size of the content controller
popover.behavior = .semitransient
popover.animates = true
popover.contentViewController = popoverContentController    
然后,要演示,请致电:

这将更新popover的位置

更新:您可能正在使用
NSSegmentedControl
,这意味着您需要特别注意传入
show
的rect。您需要在分段控件的坐标系中传递边界矩形,该坐标系描述分段的区域。下面是一个详细的示例:

// The view controller doing the presenting
class ViewController: NSViewController {

    ...

    var presentedPopover: NSPopover?

    @IBAction func selectionChanged(_ sender: NSSegmentedControl) {
        let segment = sender.selectedSegment

        if let storyboard = storyboard {
            let contentVC = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("vcPopover")) as! NSViewController

            presentedPopover = NSPopover()
            presentedPopover?.contentSize = NSSize(width: 200, height: 200)
            presentedPopover?.behavior = .semitransient
            presentedPopover?.animates = true
            presentedPopover?.contentViewController = contentVC
        }

        presentedPopover?.show(relativeTo: sender.relativeBounds(forSegment: segment), of: sender, preferredEdge: .minY)
    }

}

extension NSSegmentedControl {

    func relativeBounds(forSegment index: Int) -> NSRect {
        // Assuming equal widths
        let segmentWidth = bounds.width / CGFloat(segmentCount)

        var rect = bounds
        rect.size.width = segmentWidth
        rect.origin.x = rect.origin.x + segmentWidth * CGFloat(index)

        return rect
    }

}
请注意,
NSSegmentedControl
的扩展使用宽度计算段的近似矩形。此方法假定宽度相等,不考虑边界。您可以修改此方法以满足您的需要。可以找到有关获取iOS段帧(类似)的信息


只要同一情节提要中存在一个视图控制器,且该情节提要标识符为“vcPopover”,则此示例将被验证为正常工作。

我这样声明了我的vcPopover:
让vcPopover=NSStoryboard(名称:NSStoryboard.name(rawValue:“Main”),bundle:nil)。InstanceController(标识符:NSStoryboard.SceneIdentifier(原始值:“vPopover”))as!NSViewController
。我得到错误:“NSViewController”类型的值没有成员“show”@Ghost108我更新了我的答案,并说明了如何创建
nspover
。我尝试了你的代码,但结果是一样的,如上图所示。弹出箭头将指向第二段而不是第一段。我播放了w用
CGPoint的值(x:100.0,y:120.0)
,但没有任何变化。你可以简单地使用水平
NSButton
s或
NSSegmentedControl
?如果是后者,你从哪里得到
myButton
?@Ghost108我很抱歉。我创建了一个示例项目,并且能够使我的版本正常工作。我将把我的代码添加到我的答案中。
// The view controller doing the presenting
class ViewController: NSViewController {

    ...

    var presentedPopover: NSPopover?

    @IBAction func selectionChanged(_ sender: NSSegmentedControl) {
        let segment = sender.selectedSegment

        if let storyboard = storyboard {
            let contentVC = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("vcPopover")) as! NSViewController

            presentedPopover = NSPopover()
            presentedPopover?.contentSize = NSSize(width: 200, height: 200)
            presentedPopover?.behavior = .semitransient
            presentedPopover?.animates = true
            presentedPopover?.contentViewController = contentVC
        }

        presentedPopover?.show(relativeTo: sender.relativeBounds(forSegment: segment), of: sender, preferredEdge: .minY)
    }

}

extension NSSegmentedControl {

    func relativeBounds(forSegment index: Int) -> NSRect {
        // Assuming equal widths
        let segmentWidth = bounds.width / CGFloat(segmentCount)

        var rect = bounds
        rect.size.width = segmentWidth
        rect.origin.x = rect.origin.x + segmentWidth * CGFloat(index)

        return rect
    }

}