[ASDisplayNode] Provide safeAreaInsets and layoutMargins bridge (#685)

* [ASDisplayNode] Add safeAreaInsets, layoutMargins and related properties to ASDisplayNode

* Add layoutMargins bridged to the underlying view

* Add safeAreaInsets bridged to the underlying view

* Add fallback calculation of safeAreaInsets for old iOS versions

* Add automaticallyRelayoutOnSafeAreaChanges and automaticallyRelayoutOnLayoutMarginsChanges properties

* Add additionalSafeAreaInsets property to ASViewController for compatibility with old iOS versions

* Provide safeAreaInsets for layer-backed nodes.

This also fixes tests.

* Fix crash when insetsLayoutMarginsFromSafeArea is set from a background thread

* Changes requested at code review:
* Update documentation for layoutMargins and safeAreaInsets properties. Suggest that users set the automaticallyRelayout* flags to ensure that their layout is synchronized to the margin's values.
* Fix accessing ASDisplayNode internal structures without a lock.
* Add shortcut in -[ASDisplayNode _fallbackUpdateSafeAreaOnChildren] to skip a child when possible.
* Add shortcut in ASViewController to avoid fallback safe area insets recalculation in iOS 11. Fix fallback safe area insets recalculation when the additionalSafeAreaInsets are set.
* Add debug check that a view controller's node is never reused without its view controller, so the viewControllerRoot flag value is always consistent.
* Use getters instead of reading ivars directly in -layoutMarginsDidChange and -safeAreaInsetsDidChange.

* Minor change in CHANGELOG

* Minor change in ASDisplayNodeTests.mm
This commit is contained in:
Yevgen Pogribnyi
2018-03-27 16:29:17 +03:00
committed by Huy Nguyen
parent 063194cb1d
commit 7f01b89ddc
13 changed files with 485 additions and 3 deletions

View File

@@ -32,6 +32,7 @@
NSInteger _visibilityDepth;
BOOL _selfConformsToRangeModeProtocol;
BOOL _nodeConformsToRangeModeProtocol;
UIEdgeInsets _fallbackAdditionalSafeAreaInsets;
}
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
@@ -73,10 +74,14 @@
if (_node == nil) {
return;
}
_node.viewControllerRoot = YES;
_selfConformsToRangeModeProtocol = [self conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)];
_nodeConformsToRangeModeProtocol = [_node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)];
_automaticallyAdjustRangeModeBasedOnViewEvents = _selfConformsToRangeModeProtocol || _nodeConformsToRangeModeProtocol;
_fallbackAdditionalSafeAreaInsets = UIEdgeInsetsZero;
// In case the node will get loaded
if (_node.nodeLoaded) {
@@ -159,6 +164,20 @@
[_node recursivelyEnsureDisplaySynchronously:YES];
}
[super viewDidLayoutSubviews];
if (!AS_AT_LEAST_IOS11) {
[self _updateNodeFallbackSafeArea];
}
}
- (void)_updateNodeFallbackSafeArea
{
UIEdgeInsets safeArea = UIEdgeInsetsMake(self.topLayoutGuide.length, 0, self.bottomLayoutGuide.length, 0);
UIEdgeInsets additionalInsets = self.additionalSafeAreaInsets;
safeArea = ASConcatInsets(safeArea, additionalInsets);
_node.fallbackSafeAreaInsets = safeArea;
}
ASVisibilityDidMoveToParentViewController;
@@ -264,6 +283,25 @@ ASVisibilityDepthImplementation;
return _node.interfaceState;
}
- (UIEdgeInsets)additionalSafeAreaInsets
{
if (AS_AVAILABLE_IOS(11.0)) {
return super.additionalSafeAreaInsets;
}
return _fallbackAdditionalSafeAreaInsets;
}
- (void)setAdditionalSafeAreaInsets:(UIEdgeInsets)additionalSafeAreaInsets
{
if (AS_AVAILABLE_IOS(11.0)) {
[super setAdditionalSafeAreaInsets:additionalSafeAreaInsets];
} else {
_fallbackAdditionalSafeAreaInsets = additionalSafeAreaInsets;
[self _updateNodeFallbackSafeArea];
}
}
#pragma mark - ASTraitEnvironment
- (ASPrimitiveTraitCollection)primitiveTraitCollectionForUITraitCollection:(UITraitCollection *)traitCollection