iOS
AutoLayout

【AutoLayout】systemLayoutSizeFittingSizeでもう悩まない!

systemLayoutSizeFittingSize
何度となく忘れるので書きます

以下2つについてです

- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize;
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize 
        withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority 
              verticalFittingPriority:(UILayoutPriority)verticalFittingPriority;

公式
https://developer.apple.com/documentation/uikit/uiview/1622624-systemlayoutsizefittingsize

用途

AutoLayoutで設定したView群にコンテンツを設定した後、適切な高さ、幅を取得する際などに使います

基本

targetSizeには大抵
UILayoutFittingExpandedSize か
UILayoutFittingCompressedSize を指定します

ExpandedSizeはできるだけ大きく
CompressedSizeはできるだけ小さくします

以上

...ってところまでは、ググればいっぱい出てきます
でも何かうまく動かないことが多いので、どういう仕組みか理解していきます

UILayoutFitting??

UILayoutFittingExpandedSize、UILayoutFittingCompressedSizeはCGSizeです
ログを出せばすぐわかります

UILayoutFittingExpandedSize は (width,height) = (10000,10000)でした
UILayoutFittingCompressedSize は (width,height) = (0,0)でした

systemLayoutSizeFittingSize:UILayoutFittingCompressedSize;

これはつまり

systemLayoutSizeFittingSize:CGSizeMake(0,0);

と等価です。

でもこれだけじゃよくわかりません。

FittingPriority

UIView.hを見るとこう書いています

 - (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize NS_AVAILABLE_IOS(6_0); // Equivalent to sending  -systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority: with UILayoutPriorityFittingSizeLevel for both priorities.

つまり、以下2つが等価です。

// これと
systemLayoutSizeFittingSize:targetSize;

// これ
systemLayoutSizeFittingSize:targetSize 
        withHorizontalFittingPriority:UILayoutPriorityFittingSizeLevel
              verticalFittingPriority:UILayoutPriorityFittingSizeLevel;

UILayoutPriorityFittingSizeLevelはUILayoutPriorityの一番低いやつです(=50)

状況

つまりこういう状況です

joukyou.png

例えばsystemLayoutSizeFittingSize:UILayoutFittingCompressedSize は
(width,height)=(0,0)の赤枠に対象のViewを入れて、マージンをゼロにし、HorizontalとVerticalのLayoutPrioryを50に設定した時のAutoLayoutの結果サイズを返す
という状態です

うまく動かない時

AutoLayoutに慣れているなら、上記まで理解できればうまく動かない理由に思い当たるかと思います。

よくあるパターンとして、例えばHorizontalを固定で高さだけ取得したい場合は、横幅を固定にしてしまえばいいです

systemLayoutSizeFittingSize:CGSizeMake(self.view.frame.size.width,0)
        withHorizontalFittingPriority:UILayoutPriorityRequired
              verticalFittingPriority:UILayoutPriorityFittingSizeLevel;

(あってるよね?🤔  ここよく混乱するのでミスなどあったらすいません)