LoginSignup
16
16

More than 5 years have passed since last update.

Viewの幅で自動的に高さが決まるカスタムViewとAutoLayout

Posted at

このような性質のカスタムViewがあるとします。

  • Viewの幅が決まると同時に高さも決まる
  • Viewの幅はSuperview上のConstraintで決められ、自身では決められない

複数行表示のUILabelもその類です。自分でカスタムViewを作る時は、intrinsicContentSizeで適切なサイズを返すように実装すると良いです。

intrinsicContentSizeの実装

仮にViewの幅に対して、高さを2/3とするカスタムViewを作るとします。その場合、以下のように実装できます。

override var intrinsicContentSize: CGSize {
    guard let viewWidth = self.superview?.frame.size.width else {
        return CGSize(width: UIViewNoIntrinsicMetric, height: UIViewNoIntrinsicMetric)
    }
    return CGSize(width: UIViewNoIntrinsicMetric, height: viewWidth * 2/3)
}
  • superviewの幅を取得する
    • superviewがnilの時は、UIViewNoIntrinsicMetricを返す
    • 実際には、intrinsicContentSizeが呼ばれるタイミングでsuperviewがnilになることはないと思われるが念のため
  • その幅を元に高さを計算し、CGSizeで返す
    • 幅は自身で決めるものではないので、UIViewNoIntrinsicMetricを返す

例なので簡単なものにしていますが、実際は、UILabelなど複数のViewを配置し、サイズが可変するようなカスタムViewを作る場合があると思います。その時は、UILabel#sizeThatFitsを呼ぶなどして、適切なサイズを計算し返す必要があります。

Interface Builder上での配置

仮にこのカスタムViewのクラス名をMyCustomViewとします。

  • Interface BuilderでViewをSuperviewに配置
  • ViewのIdentity InspectorのClassにMyCustomViewと入力
  • そのViewのHeight Constraintとして以下の2つを付ける
    • RelationをEqual、Constantを取りうる最小の高さ、PriorityをHigh(750)にしたもの
    • RelationをGreater Than or Equal、Constantを取りうる最小の高さ、PriorityをRequired(1000)にしたもの

このようにすると、カスタムViewはinstrinsicContentSizeに従って、自動的にリサイズされるようになります。

動的に高さが変わる場合

プロパティを設定し直すと、カスタムViewの表示内容が変更され、サイズが変わる場合があると思います。その場合は、invalidateIntrinsicContentSize()を呼びます。そうすると、intrinsicContentSizeが適切なタイミングで呼ばれリサイズします。

多層的に配置するとうまくリサイズされない場合

UITableViewCellなどにカスタムViewを配置すると、Viewのサイズ(frame.size)が最終決定するタイミングとintrinsicContentSizeが呼び出されるタイミングにズレが生じ、うまくリサイズされないことがあります。その場合は、layoutSubviewsでinvalidateIntrinsicContentSizeを呼ぶと解決します。ただし、良い手かどうかはわかりませんので自己責任で・・・。自分の環境では問題は起きていません。

override func layoutSubviews() {
    invalidateIntrinsicContentSize()
    super.layoutSubviews()
}
16
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
16