NSWindow 宽度未使用 setFrame(frame, display, animate) 更新

Posted

技术标签:

【中文标题】NSWindow 宽度未使用 setFrame(frame, display, animate) 更新【英文标题】:NSWindow width not updated using setFrame(frame, display, animate) 【发布时间】:2019-03-26 12:11:36 【问题描述】:

我是 macOS 的新手。我正在为 macos 开发一个应用程序,我希望用户在其中拥有侧面板,并且他可以根据需要隐藏/取消隐藏。

我使用split view 将我的屏幕分成 3 个部分。左右面板具有与视图成比例的宽度(不是拆分视图)。

我想要的是当用户隐藏左面板时,左面板应该隐藏自己,窗口的左锚应该向右移动,右锚应该保持在它的位置。

同样,如果用户隐藏右侧面板,右侧面板也应该被隐藏。窗口的右锚应该向左移动,左锚应该保持在它的位置。

当用户想要隐藏/取消隐藏左侧面板时,会调用以下函数。

guard let window = self.view.window else 
            return
        
        var frame = window.frame

    if window.isZoomed 
        if leftPane.contentView!.isHidden 
            self.leftPane.isHidden = false
            self.leftPane.contentView?.isHidden = false
         else 
            self.leftPane.contentView?.isHidden = true
        
     else 
        if leftPaneHidden 
            self.leftPane.isHidden = false
            frame = NSRect(x: (frame.origin.x - leftPane.frame.size.width), y: frame.origin.y, width: (frame.size.width + leftPane.frame.size.width), height: frame.size.height)
            leftPaneHidden = false
         else 
            self.leftPane.isHidden = true
            frame = NSRect(x: (frame.origin.x + leftPane.frame.size.width), y: frame.origin.y, width: (frame.size.width - leftPane.frame.size.width), height: frame.size.height)
            leftPaneHidden = true
        

        self.view.window?.setFrame(frame, display: true, animate: true)

我希望隐藏左侧面板,因为它可以在 notability 应用中使用。

【问题讨论】:

澄清一下,您是说要缩小封闭窗口吗? 我想隐藏面板。确保没有其他面板扩展其宽度。我不希望它像 xcode 一样工作。我希望它像知名应用一样工作。 假设窗口大小为 100。面板每个宽度为 15。如果一次隐藏一个面板,则窗口宽度应为 85。如果两个面板都隐藏,则窗口宽度应为 70。 查看我的示例。照原样,它应该做你想做的事。 (而且,如果它对您有帮助并且您不介意,请检查并投票!) 【参考方案1】:

如果您确实想要缩小/扩大窗口,这里有一个工作演示。如果您希望它以 Xcode 的方式工作,请删除框架的混乱。它以编程方式实现,因此我不必描述情节提要,但您可以轻松地使用情节提要做同样的事情。左右视图中唯一的代码设置了背景颜色,以便您可以看到它的工作原理。

SplitViewController:

class MainSplitViewController: NSSplitViewController 
    weak var leftItem: NSSplitViewItem?
    weak var rightItem: NSSplitViewItem?

    convenience init(identifier: NSUserInterfaceItemIdentifier) 
        self.init()
        splitView.identifier = identifier
        splitView.wantsLayer = true
        splitView.layer?.backgroundColor = NSColor.darkGray.cgColor
        splitView.dividerStyle = .thin

        let vcL = SubViewController(NSView(), backgroundColor: .red)
        let vcM = MainViewController(MainView(self), backgroundColor: .green)
        let vcR = SubViewController(NSView(), backgroundColor: .blue)

        vcL.view.widthAnchor.constraint(greaterThanOrEqualToConstant: 100).isActive = true
        vcM.view.widthAnchor.constraint(greaterThanOrEqualToConstant: 100).isActive = true
        vcR.view.widthAnchor.constraint(greaterThanOrEqualToConstant: 100).isActive = true

        let sidebarItem = NSSplitViewItem(viewController: vcL)
        sidebarItem.canCollapse = true
        sidebarItem.holdingPriority = NSLayoutConstraint.Priority(NSLayoutConstraint.Priority.defaultLow.rawValue + 1)
        addSplitViewItem(sidebarItem)
        leftItem = sidebarItem

        let mainItem = NSSplitViewItem(viewController: vcM)
        addSplitViewItem(mainItem)

        let inspItem = NSSplitViewItem(viewController: vcR)
        inspItem.canCollapse = true
        inspItem.holdingPriority = NSLayoutConstraint.Priority(NSLayoutConstraint.Priority.defaultLow.rawValue + 1)
        addSplitViewItem(inspItem)
        rightItem = inspItem
    

中间视图,带有切换侧视图的按钮:

class MainView: NSView, DebugHelper 
    weak var splitViewController: MainSplitViewController?

    func labeledButton(_ stringValue: String = "") -> NSButton 
        let button = NSButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.heightAnchor.constraint(equalToConstant: 28.0)
        button.bezelStyle = NSButton.BezelStyle.rounded
        button.title = stringValue
        return button
    
    private func adjustWindowFrame(_ item: NSSplitViewItem, left: Bool) 
        let view = item.viewController.view
        let frame = window!.frame
        if item.isCollapsed 
            let minX = left ? frame.minX - view.frame.width : frame.minX
            let newFrame = NSRect(x: minX, y: frame.minY, width: frame.width + view.frame.width, height: frame.height)
            window!.setFrame(newFrame, display: true)
         else 
            let minX = left ? frame.minX + view.frame.width : frame.minX
            let newFrame = NSRect(x: minX, y: frame.minY, width: frame.width - view.frame.width, height: frame.height)
            window!.setFrame(newFrame, display: true)
        
        item.isCollapsed = !item.isCollapsed
    
    @objc func collapseLeft(_ sender: Any) 
        guard let item = splitViewController?.leftItem else  return 
        adjustWindowFrame(item, left: true)
    
    @objc func collapseRight(_ sender: Any) 
        guard let item = splitViewController?.rightItem else  return 
        adjustWindowFrame(item, left: false)
    

    convenience init(_ parent: MainSplitViewController) 
        self.init(frame: .zero)
        splitViewController = parent
        translatesAutoresizingMaskIntoConstraints = false

        let lButton = labeledButton("Collapse Left")
        addSubview(lButton)
        lButton.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -20).isActive = true
        lButton.centerXAnchor.constraint(equalTo: centerXAnchor, constant: -100).isActive = true
        lButton.action = #selector(collapseLeft)
        lButton.target = self

        let rButton = labeledButton("Collapse Right")
        addSubview(rButton)
        rButton.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -20).isActive = true
        rButton.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 100).isActive = true
        rButton.action = #selector(collapseRight)
        rButton.target = self
    


class MainViewController: NSViewController 

    convenience init(_ view: NSView, backgroundColor: NSColor = .white) 
        self.init()
        self.view = view
        self.view.wantsLayer = true
        self.view.layer?.backgroundColor = backgroundColor.cgColor
    


【讨论】:

以上是关于NSWindow 宽度未使用 setFrame(frame, display, animate) 更新的主要内容,如果未能解决你的问题,请参考以下文章

指定单元格 imageView 的宽度

我可以在同一个视图上使用 setFrame 和 autolayout 吗?

UIView setFrame 线程安全

setTranslatesAutoresizingMaskIntoConstraints和setFrame组合使用导致的异常

调整窗口大小时带有约束的宽度限制

在使用情节提要和 swift 时从 xib 打开 NSWindow