NSWindow - 调整大小时缩放所有内容

Posted

技术标签:

【中文标题】NSWindow - 调整大小时缩放所有内容【英文标题】:NSWindow - scale all content when resizing 【发布时间】:2022-01-02 04:41:50 【问题描述】:

我无法弄清楚如何完成看似非常简单的任务。我有一个 macOS 可可应用程序,它由一个带有自定义视图的窗口组成。视图为 600x500 点。在这个视图内部是一个子视图,它跨越了主视图的整个宽度,但只是视图高度的一小部分。它的垂直原点大约在 y=200。

子视图从左右边界开始 20 点开始绘制一个矩形,高度约为 30 点。它还使用它的层和一个 CAEmitter 层作为子层。这个发射器的位置可以由用户控制,因此它的位置将由从视图外部调用的函数更新。

我想要什么:

当用户调整窗口大小时,它应该只按比例缩放(我设法做到了),以便窗口的内容作为一个整体得到调整大小。任何子视图都不应该以任何方式重新排列,它们都应该保持它们的大小和位置相对于彼此,只是变大/变小。

我没有让这个工作。

到目前为止我所尝试的:

如果没有设置其他属性,我可以调整窗口大小,但是 subiew 根本不缩放,它坚持它在 监督。 我为 trailingAnchor 设置了subView.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor).isActive = true 和相同的设置,另外我设置了subView.autoresizingMask = [.width] 现在子视图中绘制的矩形的宽度得到了调整,但矩形的边缘远离边界 20 个点。我也想缩放这个距离。 矩形的高度保持不变。当我将-heigth 添加到子视图的自动调整大小蒙版时,高度会以一种非常不成比例的方式扭曲(到顶部和底部边距的距离保持不变,因此虽然子视图的高度在开始时只有大约 30,但矩形在调整大小时会被炸毁. 发射器未重新定位。它的水平位置是根据用户交互计算的,并且是相对于视图的边框,在调整大小后它会保持在其绝对位置。我通过调用 draw() 方法的计算函数解决了这个问题,但这对我来说似乎不正确

在 cocoa 框架中有太多关于大小、锚点、约束等的入口点,我根本不知道从哪里开始,所以任何帮助将不胜感激。

更新:我添加了精简到最小值的代码:

class MyViewController: NSViewController 

    public init () 
        super.init(nibName: nil, bundle: nil)
        self.view = MyView(frame: NSRect(x: 0, y: 0, width: 600, height: 500))
    

    required init?(coder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    


class MyView: NSView 

    override init(frame frameRect: NSRect) 
    
        super.init(frame: frameRect)
    
        let subView = MySubView(frame: NSRect(x: 0, y: frame.height/3, width: frame.width, height: frame.height/10))
        self.addSubview(subView)
        subView.autoresizingMask = [.width, .height]
        subView.translatesAutoresizingMaskIntoConstraints = true
        subView.trailingAnchor.constraint(greaterThanOrEqualTo: self.trailingAnchor).isActive = true
        subView.leadingAnchor.constraint(greaterThanOrEqualTo: self.leadingAnchor).isActive = true
    

    required init?(coder decoder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    



class MySubView: NSView 

    override func draw(_ dirtyRect: NSRect) 
    
        let context = NSGraphicsContext.current!.cgContext
        context.setStrokeColor(.black)
        context.setFillColor(CGColor.init(red: 0.7, green: 0.7, blue: 0.7, alpha: 1))
        context.setLineWidth(2)
    
        let borderRect = CGRect(x: constant.sideMargin, y: 5, width: frame.width-2*constant.sideMargin, height: frame.height-10)
        let roundedRect = CGPath.init(roundedRect: borderRect, cornerWidth: 5, cornerHeight: 5, transform: nil)
    
        context.addPath(roundedRect)
        context.fillPath()
        context.strokePath()
    
        context.addPath(roundedRect)
        context.strokePath()
     

【问题讨论】:

setBoundsSize 是您要找的吗? 提示:如果translatesAutoresizingMaskIntoConstraints 未关闭,autoresizingMask 将转换为约束。 Xcode 可以在运行时显示视图和约束。 文档:View Geometry in View Programming Guide。 说实话,我还是没有头绪。我在精简版本中添加了我的代码。在 AppDelegate 中,我将窗口设置为固定的纵横比。调整窗口大小时,子视图内容(矩形)的左右边缘跟随边框,但即使这不是我想要的。它应该保持它的相对距离,所以边距应该变大一点。矩形的上边距似乎固定在视图的中心,而不是停留在高度的 ⅓。我迷路了!!! 【参考方案1】:

如View Programming Guide 中所述,如果boundsframe 不同,NSView 将缩放和偏移其内容。当frame 更改时,只需将bounds 设置为600, 500。视图的子视图不需要约束,因为它们的坐标不会改变。

MyView 设置代码:

// frame changed notitication
self.postsFrameChangedNotifications = true
self.frameChangeObserver = NotificationCenter.default.addObserver(forName: NSView.frameDidChangeNotification,
    object: self, queue: OperationQueue.main)  (note) in
    self.setBoundsSize(NSSize(width:600, height: 500))


let subView = MySubView(frame: NSRect(x: 0, y: bounds.height/3, width: bounds.width, height: bounds.height/10))
// no constraints
subView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(subView)

【讨论】:

非常感谢。我知道解决方案应该不会太复杂,但我从来没有想过我必须设置回调。

以上是关于NSWindow - 调整大小时缩放所有内容的主要内容,如果未能解决你的问题,请参考以下文章

为啥添加约束会消除调整 NSWindow 大小的能力?

NSLayoutConstraint 防止 NSWindow 调整大小

为啥设置约束后不能再调整 NSWindow 的大小?

如何在不缩放其内容的情况下调整 opengl 视口大小

双击透明 NSWindow 标题不会最大化窗口

Cocoa 查看自动缩放内容