Home > other >  NSLayoutConstraint for setting Min and Max view width
NSLayoutConstraint for setting Min and Max view width

Time:09-13

What I want to achieve in AppKit (not in SwiftUI): [GIF] (example in SwiftUI)

  • The NSWindow max width should not be limited to the NSTextField max width.
  • The NSWindow min width should be limited to the NSTextField min width.
  • NSTextField need to have these parameters: [min width: 200, max width: 400]

I had several attempts to implement this behavior in AppKit. I've been trying to do this for a few days now, but it doesn't work. [PIC] [GIF]

I tried to set the low priority on Leading / Trailing constraint.
This partially fixed the situation. I was able to change the size of the window normally, but the window size was not limited to the minimum size of NSTextField. [GIF]

CodePudding user response:

The important thing to notice here is that you only want the low priority constraints to be one way. That is, you don't want something like this:

// throughout the answer, I use "tf" for the text field, and "view" for its superview
let weakLeadingConstraint = tf.leadingAnchor.constraint(equalTo: view.leadingAnchor)
let weakTrailingConstraint = tf.trailingAnchor.constraint(equalTo: view.trailingAnchor)
weakLeadingConstraint.priority = .dragThatCannotResizeWindow
weakTrailingConstraint.priority = .dragThatCannotResizeWindow

Because these constraints would break when the window is resized, allowing the window to be resizable to any width where the leading and trailing anchors are "not equal" to those of the text field.

Instead, the low priority constraints should be >= or <= constraints. Think of the 2 equality constraints as the following 4 inequality constraints:

  • tf.leading <= view.leading
  • tf.trailing >= view.trailing
  • tf.leading >= view.leading
  • tf.trailing <= view.trailing

It is the first 2 that you want to break, leaving the last 2 (which says that the text field should always be within the window) in tact, when you resize the window.

The other constraints are quite straightforward, so I'll just present the whole code here:

tf.translatesAutoresizingMaskIntoConstraints = false

let weakLeadingConstraint = tf.leadingAnchor.constraint(lessThanOrEqualTo: view.leadingAnchor)
let weakTrailingConstraint = tf.trailingAnchor.constraint(greaterThanOrEqualTo: view.trailingAnchor)
weakLeadingConstraint.priority = .dragThatCannotResizeWindow
weakTrailingConstraint.priority = .dragThatCannotResizeWindow

NSLayoutConstraint.activate([
    tf.centerXAnchor.constraint(equalTo: view.centerXAnchor),
    tf.centerYAnchor.constraint(equalTo: view.centerYAnchor),
    tf.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor),
    tf.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor),
    weakLeadingConstraint,
    weakTrailingConstraint,
    tf.widthAnchor.constraint(greaterThanOrEqualToConstant: 200),
    tf.widthAnchor.constraint(lessThanOrEqualToConstant: 400),
])
  • Related