NSWindow - 调整大小时缩放所有内容
NSWindow - scale all content when resizing
我不知道如何完成这个看起来很简单的任务。我有一个 macOS cocoa 应用程序,它由一个 window 组成,里面有一个自定义视图。视图是 600x500 点。在这个视图中是一个子视图,它横跨主视图的整个宽度,但只占视图高度的一小部分。它的垂直原点大约在 y=200。
子视图从距左右边界 20 点开始绘制一个矩形,高度约为 30 点。它还将其层与 CAEmitter 层一起用作子层。该发射器的位置可由用户控制,因此其位置将通过从视图外部调用的函数进行更新。
我想要的:
当用户调整 window 的大小时,它应该只按比例缩放(我设法做到了),以便 window 的内容作为一个整体得到调整。任何子视图都不应该以任何方式重新排列,它们都应该保持它们的大小和相对于彼此的位置,只是得到 bigger/smaller.
我无法使用它。
到目前为止我尝试过的:
- 在没有设置其他属性的情况下,我可以调整 window 的大小,但是
子视图根本不缩放,它坚持它在
超级视图。
- 我设置了
subView.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor).isActive = true
和 trailingAnchor 一样,另外我设置了 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()
}
}
如 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)
我不知道如何完成这个看起来很简单的任务。我有一个 macOS cocoa 应用程序,它由一个 window 组成,里面有一个自定义视图。视图是 600x500 点。在这个视图中是一个子视图,它横跨主视图的整个宽度,但只占视图高度的一小部分。它的垂直原点大约在 y=200。
子视图从距左右边界 20 点开始绘制一个矩形,高度约为 30 点。它还将其层与 CAEmitter 层一起用作子层。该发射器的位置可由用户控制,因此其位置将通过从视图外部调用的函数进行更新。
我想要的:
当用户调整 window 的大小时,它应该只按比例缩放(我设法做到了),以便 window 的内容作为一个整体得到调整。任何子视图都不应该以任何方式重新排列,它们都应该保持它们的大小和相对于彼此的位置,只是得到 bigger/smaller.
我无法使用它。
到目前为止我尝试过的:
- 在没有设置其他属性的情况下,我可以调整 window 的大小,但是 子视图根本不缩放,它坚持它在 超级视图。
- 我设置了
subView.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor).isActive = true
和 trailingAnchor 一样,另外我设置了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()
}
}
如 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)