hnh
hnh

Reputation: 14795

Proportionally adjust layout height when the intrinsic size overflows the available width

I'm playing with a (macOS) today list widget and I'm using autolayout to size the widget. That widget contains a custom NSView, rendering some preformatted text (pretty much like an HTML pre tag).

Based on the text being rendered the widget has an intrinsic content size. It also scales properly (down or up) and centeres if the set frame is bigger or smaller than the intrinsic size.

This generally works well in many scenarios, except one. When being shown as a Today widget, the width of the widget is constrained to a specific size. Which is fine even if the intrinsic size is bigger than the available width, it'll scale down. However it seems that autolayout still seems to use the intrinsic height of the widget as-is, despite that the width got constrained. That way my view appears padded on the height, like so:

/------------------\
|    extra pad     |
|------------------|
|                  |
|  downsized view  |
|                  |
|------------------|
|    extra pad     |
\------------------/

Example: intrinsic size of view being rendered 800x400, width of today view 400. View gets scaled down propertionally to 400x200, but the layout height still seems to be the original 400 (200 padding at top & bottom).

Question: how do I tell autolayout to take the scaling into account. It sounds almost like something like -intrinsicSizeForMaxSize: would be needed.

I tried setting a width/height ratio constraint, reducing compression resistance and increasing hugging priority, but that doesn't kill the extra padding. I think I'm missing something on how autolayout considers the intrinsic size when it overflows.

Upvotes: 0

Views: 65

Answers (1)

hnh
hnh

Reputation: 14795

Switched from using an intrinsic size to a ratio constraint. I still calculate the 'native' size of the view, but only use that to figure out the width/height ratio. Then I add a constraint to keep that ratio. Seems to work fine. Here is the relevant code:

  let size  = nativeSize // calculate the desired size
  let ratio = size.height / size.width

  if let rc = ratioConstraint {
    rc.isActive = false
    removeConstraint(rc)
  }

  ratioConstraint =
    NSLayoutConstraint(item:   self, attribute: .height, relatedBy: .equal,
                       toItem: self, attribute: .width,
                       multiplier: ratio, constant: 0)
  ratioConstraint?.isActive = true

Then I just pin the view to the container via |[self]| for both horizontal and vertical.

Upvotes: 0

Related Questions