TextureGroup / Texture

Smooth asynchronous user interfaces for iOS apps.
https://texturegroup.org/
Other
8.01k stars 1.29k forks source link

Layouts based on trait collections are initially wrong (trait collection is .unspecified) #258

Open fruitcoder opened 7 years ago

fruitcoder commented 7 years ago

I have a simple ASViewController that handles its node's layout through the layoutSpecBlock. I want to have different layouts based on whether the horizontal size class is .regular or not. Unfortunately, when the view controller is presented initially (modally, on an iPhone 6+ Landscape) the node.environmentTraitCollection().horizontalSizeClass is .unspecified for every call to the layoutSpecBlock. Once I rotate the device back and forth, the value is correct. This happens probably because the node isn't yet part of the hierarchy and can therefore not infer the size classes. I tried calling setNeedsLayout() in viewWillAppear() but it's still .unspecified at this point.

Current workaround ist to check if node.environmentTraitCollection().containerSize.width >= 568.0 but I wanted to know if there is any way I can work around this.

maicki commented 7 years ago

@fruitcoder I think this the default behavior also in plain UIKit case. If the view / view controller is not in the view hierarchy the trait collection is always .unspecified. We are propagate the new trait collection from the view controller down as soon as the trait collection changes:

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
  [super traitCollectionDidChange:previousTraitCollection];

  ASPrimitiveTraitCollection traitCollection = [self primitiveTraitCollectionForUITraitCollection:self.traitCollection];
  traitCollection.containerSize = self.view.bounds.size;
  [self propagateNewTraitCollection:traitCollection];
}
fruitcoder commented 7 years ago

Thanks! Does that mean I can override traitColectionDidChangeand call setNeedsLayout so the layout spec is reevaluated or won't layoutSpecThatFits: be called because the constrainedSizeForCalculatedLayout might the same?

maicki commented 7 years ago

@fruitcoder An ASViewController reacts on trait collection changes by itself:

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
  [super traitCollectionDidChange:previousTraitCollection];

  ASPrimitiveTraitCollection traitCollection = [self primitiveTraitCollectionForUITraitCollection:self.traitCollection];
  traitCollection.containerSize = self.view.bounds.size;
  [self propagateNewTraitCollection:traitCollection];
}

And in propagateNewTraitCollection we propagate the new trait collection the node tree as well as call layoutThatFits: on the root node. So it should automatically reevaluate layoutSpecThatFits: in this case.

Could you verify what is happening on your side if the trait collection changes? E.g. set a breakpoint in traitCollectionDidChange in ASViewController and see what is happening. Thanks!