Commit Graph

2 Commits

Author SHA1 Message Date
Dustin Shahidehpour
4b61cdccea Add flag to not include view in layout.
Summary:
When dealing with manual sizing in UIView's (or UIKit in general) we see a common pattern like so:

Below we have an example implementation of a view with two Labels that want to be stacked horizontally. If we don't pass a second string, we hide the second label and give up the available space to the first label. See below:

```
interface TitleSubtitleView : UIView

- (void)configureWithTitle:(NSString *)title subtitle:(NSString *)subtitle;

end

implementation {
  UILabel *_titleLabel;
  UILabel *_subtitleLabel;
}

....

- (void)configureWithTitle:(NSString *)title subtitle:(NSString *)subtitle {
  _titleLabel.text = title;
  if (subtitle.length > 0) {
    _subtitleLabel.hidden = NO;
    _subtitleLabel.text = subtitle;
  } else {
    _subtitleLabel.hidden = YES;
  }
}

- (CGSize)sizeThatFits:(CGSize)size {
  const CGSize titleSize = [_titleLabel sizeThatFits:size];
  CGSize subtitleSize = CGSizeZero;
  if (!_subtitleLabel.isHidden) {
    subtitleSize = [_subtitleSize sizeThatFits:CGSizeMake(size.width - titleSize.width, size.height - titleSize.height)];
  }
}

- (void)layoutSubviews {
  [super layoutSubviews];

  const CGSize titleSize = [_titleLabel sizeThatFits:size];
  _titleLabel.frame = CGRectMake(0, 0, titleSize.width, titleSize.height);
  if (!_subtitleLabel.isHidden) {
    subtitleSize = [_subtitleSize sizeThatFits:CGSizeMake(size.width - titleSize.width, size.height - titleSize.height)];
    _subtitleLabel.frame = CGRectMake(CGRectGetMaxX(_titleLabel.frame), 0, subtitleSize.width, subtitleSize.height);
  }

}
```

The problem is with the CSSLayout framework, as long as your view is in hierarchy, it's going to be allocated space during layout calculation. The only way to fix the view above would be to completely remove it from view hierarchy if it isn't being used. The problem is that adding/removing views from hierarchy is much less performant than hiding.

As a result, we need a way to tell the CSSLayoutKit library that even though a view is in hierarchy, we don't want to include it in layout. With this diff, we could change the class to look like this:

```
interface TitleSubtitleView : UIView

- (void)configureWithTitle:(NSString *)title subtitle:(NSString *)subtitle;

end

implementation {
  UILabel *_titleLabel;
  UILabel *_subtitleLabel;
}

....

- (void)configureWithTitle:(NSString *)title subtitle:(NSString *)subtitle {
  _titleLabel.text = title;
  _subtitleLabel.text = subtitle;

  const BOOL subtitleHasText = subtitle.length > 0;
  _subtitleLabel.hidden = !subtitleHasText;
  [_subtitleLabel css_includeInLayout:!subtitleHasText];
}

- (CGSize)sizeThatFits:(CGSize)size {
  const intrinsicSize = [self css_intrinsicSize];
  return CGSizeMake(MIN(size.width, intrinsicSize.width), MIN(size.height, intrinsicSize.height)));
}

- (void)layoutSubviews {
  [super layoutSubviews];

  [self css_applyLayout];
}
```

Reviewed By: emilsjolander

Differential Revision: D4189897

fbshipit-source-id: 403d11d84d47691e3ce0b5ac18a180b0e4c104c4
2016-11-17 08:37:34 -08:00
Dustin Shahidehpour
56aa279fef BREAKING: remove css_sizeThatFits:, replace with new API.
Summary: When I try to use this in practice, I have come to realize that css_sizeThatFits will 99% return to you the constrainedSize that you pass it, thus making it useless. Instead, we replace it with a new API that will tell you the optimal size of the resolved layout. From this we can choose to use that size, or scale it down.

Reviewed By: emilsjolander

Differential Revision: D4191873

fbshipit-source-id: d36a2850448d9d82f97e5ef4c7397778c2a14094
2016-11-17 07:37:32 -08:00