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 中所述,如果bounds
与frame
不同,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 - 调整大小时缩放所有内容的主要内容,如果未能解决你的问题,请参考以下文章