ひtoりgoと

Auto Layout で幅に応じて Label(NSTextField)を折り返す

macOS 開発

AppKit で Label といえば、NSLabel ...ではなく NSTextField を使う。それを Auto Layout 1で扱うのが今日のテーマだ。

単純に配置するだけなら何も考えなくていいけど、必要な幅が長くなったら下の GIF アニメーションのように折り返したい。

横に縮むと縦に伸びる

こうやって上下左右に Constraint を追加しただけの単純なウインドウで考えてみよう:

シンプルな Constraint

Interface Builder だけでできるよ!

調べるとサブクラスを作って layout() のタイミングで preferredMaxLayoutWidth を指定するみたいな大掛かりな話ばかり。

Word Wrap
水平圧縮抵抗は弱め

そんなはずはないと思って Interface Builder で Line Break を Word Wrap にして水平方向の Content Compression Resistance Priority を下げただけでできた。それが冒頭の GIF アニメーションの状態だ。なんだ、簡単じゃん。

いつから使える...?

気になるのはどのバージョンから対応しているかだ。昔はできなかった気がして試しに上で作ったサンプル App を VMware 上の Yosemite で動かしてみたらまったくダメだった。改行なんてしてくれない。いつからできるようになったのだろうか。

こういうときに頼りになるのが NSTextField のリファレンス...ではなく、例によって AppKit Release Notes だ。検索すると、まさにこの変更の記載「NSTextField intrinsicContentSize improvements」が OS X 10.11 のところにあった。

Previously, unless NSTextField’s preferredMaxLayoutWidth was set to something other than 0, the -intrinsicContentSize method would measure the text field with its contents on a single line, even if wrapping was enabled. Because of this behavior, the auto layout engine would not be able to find a size for a text field that spanned multiple lines, even though doing so would produce an acceptable and aesthetically better layout.

We’ve changed things such that the autolayout engine provides a width that acts like the preferredMaxLayoutWidth for the NSTextField, allowing for a text field to reflow into multiple lines. This works only for apps linked against 10.11 that have wrapping text and a preferredMaxLayoutWidth of 0. Also, it only works if the constraints on the text field allow for content compression.

preferredMaxLayoutWidth を与えなくても適当に判断してくれるらしい。このほか Attributed String を使った場合の注意点なども書いてる。preferredMaxLayoutWidth の挙動にも関わってくるようで、Label を Auto Layout で並べたい人は目を通しておくとよさそうだ2

2020.11.2 追記

気になって UIKit の世界も調べてみたら

Automatic Preferred Max Layout Width is not available on iOS versions prior to 8.0

ということらしい。

Yosemite はまだ切れないことが多いけどさすがに iOS 8 はサポートしなくてもよさそうなので、Auto Layout なのに UILabel.preferredMaxLayoutWidth を手動で指定しているコードを見つけたらほとんどが取り除けるかも。


  1. 個人的には Auto Layout は行単位のリストで完結することが多い iOS よりも環境設定ウインドウをはじめとして UI 部品が縦横方向に積み重なる Mac App でこそ活きる気がしている。言語ごとの変化まで考えるとこれがない世界には戻れない。 ↩︎

  2. なぜかことあるごとに過去のリリースノートを読まないといけない世界。今回だったら NSTextField.preferredMaxLayoutWidth のリファレンスにも書くのが妥当だと思うのだが... ↩︎

Share

リンクも共有もお気軽に。記事を書くモチベーションの向上に役立てます。

© 2005-2020 zumuya