Dmitry
Dmitry

Reputation: 733

What is a correct way to report desired size for UIView subclass?

I am subclassing UIView and cannot find a right way to request/report its desired size. I expected systemLayoutSizeFittingSize to do the trick, but it is never called. Layout is simple - I pin top and leading of my view and limit trailing and bottom to be less than or equal to top-level view. Among all sizing functions, only intrinsicContentSize is called, but that one is not very helpful.

import Foundation
import UIKit

class StatsView: UIView
{
  override func drawRect(rect: CGRect)
  {
    let context=UIGraphicsGetCurrentContext()!
    CGContextSetRGBFillColor(context, 0, 0, 1, 1)
    CGContextFillRect(context, rect)
  }

  override func sizeThatFits(size: CGSize) -> CGSize
  {
    print("Called sizeThatFits with \(size)")
    if(size.width>350)
    {
      return CGSize(width: 350,height: 50)
    }
    else
    {
      return CGSize(width: 50,height: 100)
    }
  }

  override func systemLayoutSizeFittingSize(size: CGSize) -> CGSize
  {
    print("Called systemLayoutSizeFittingSize with \(size)")
    return super.systemLayoutSizeFittingSize(size)
  }

  override func systemLayoutSizeFittingSize(size: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize
  {
    print("Called systemLayoutSizeFittingSize with \(size)")
    if(size.width>350)
    {
      return CGSize(width: 350,height: 50)
    }
    else
    {
      return CGSize(width: 50,height: 100)
    }
  }

  override func intrinsicContentSize() -> CGSize
  {
    super.intrinsicContentSize()
    print("Called intrinsicContentSize")
    return CGSize(width: 10,height: 50)
  }
}

What is a right way to do it?

Update I want my view to have some info, not just a blue rectangle. There is some "optimal" width, but if the view cannot have that much from its parent, it can compensate by rearranging information to use more height. So, reporting constant values from intrinsicContentSize does not fit my needs.

Upvotes: 6

Views: 2144

Answers (2)

Shamim Hossain
Shamim Hossain

Reputation: 1760

Please note that in auto-layout environment systemLayoutSizeFittingSize will not call even it change layout. It's a method to calculate the size of a view after view did finished layout.

The intrinsic content size is concerned only with data that is in the view itself, not in other views. Remember that you can also set constant width or height constraints on any view, and you don't need to override instrinsicContentSize if these dimensions won't be changing with changing view content

View will update it's content size if there is any update of it's constraint which is happened using - (void)updateConstraints method that means you could override this method to observe the changes of it's constraints. Since you wants to rearrange views in certain width condition so best practice is to put on this - (void)layoutSubviews method which will called on changes of view's frame.

- (void)layoutSubviews { 
    [super layoutSubviews];
    // do your view arrangement based on width
    // apple custom constraint here
}

Upvotes: 2

Scott H
Scott H

Reputation: 1529

You use intrinsicContentSize to report the desired size of your view based off of it's contents. This value can change as the contents change, but you need to call invalidateIntrinsicContentSize when it does.

This intrinsicContentSize works along with contentHuggingPriority, contentCompressionResistancePriority, and the other layout constraints in the superview to determine the actual layout size.

In your case it sounds like you want to report an ideal size based off of the contents of your view, change the size and invalidate it if the content changes, and use layout constraints with sibling views and the parent view to compress (or resist) as needed.

Upvotes: 7

Related Questions