ASDisplayNode.mm
canLayoutAsynchronous
1
2
3
4
- (BOOL)canLayoutAsynchronous
{
return !self.isNodeLoaded;
}
__setNeedsLayout
1
2
3
4
- (void)__setNeedsLayout
{
[self invalidateCalculatedLayout];
}
invalidateCalculatedLayout
1
2
3
4
5
6
7
8
9
10
11
12
- (void)invalidateCalculatedLayout
{
MutexLocker l(__instanceLock__);
_layoutVersion++;
_unflattenedLayout = nil;
#if YOGA
[self invalidateCalculatedYogaLayout];
#endif
}
__layout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
- (void)__layout
{
ASDisplayNodeAssertThreadAffinity(self);
// ASAssertUnlocked(__instanceLock__);
BOOL loaded = NO;
{
AS::UniqueLock l(__instanceLock__);
loaded = [self _locked_isNodeLoaded];
CGRect bounds = _threadSafeBounds;
if (CGRectEqualToRect(bounds, CGRectZero)) {
// Performing layout on a zero-bounds view often results in frame calculations
// with negative sizes after applying margins, which will cause
// layoutThatFits: on subnodes to assert.
as_log_debug(OS_LOG_DISABLED, "Warning: No size given for node before node was trying to layout itself: %@. Please provide a frame for the node.", self);
return;
}
// If a current layout transition is in progress there is no need to do a measurement and layout pass in here as
// this is supposed to happen within the layout transition process
if (_transitionID != ASLayoutElementContextInvalidTransitionID) {
return;
}
as_activity_create_for_scope("-[ASDisplayNode __layout]");
// This method will confirm that the layout is up to date (and update if needed).
// Importantly, it will also APPLY the layout to all of our subnodes if (unless parent is transitioning).
l.unlock();
[self _u_measureNodeWithBoundsIfNecessary:bounds];
l.lock();
[self _locked_layoutPlaceholderIfNecessary];
}
[self _layoutSublayouts];
// Per API contract, `-layout` and `-layoutDidFinish` are called only if the node is loaded.
if (loaded) {
ASPerformBlockOnMainThread(^{
[self layout];
[self _layoutClipCornersIfNeeded];
[self _layoutDidFinish];
});
}
[self _fallbackUpdateSafeAreaOnChildren];
}
_layoutDidFinish
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
- (void)_layoutDidFinish
{
ASDisplayNodeAssertMainThread();
// ASAssertUnlocked(__instanceLock__);
ASDisplayNodeAssertTrue(self.isNodeLoaded);
[self layoutDidFinish];
}
#pragma mark Calculation
- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize
restrictedToSize:(ASLayoutElementSize)size
relativeToParentSize:(CGSize)parentSize
{
as_activity_scope_verbose(as_activity_create("Calculate node layout", AS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT));
as_log_verbose(ASLayoutLog(), "Calculating layout for %@ sizeRange %@", self, NSStringFromASSizeRange(constrainedSize));
#if AS_KDEBUG_ENABLE
// We only want one calculateLayout signpost interval per thread.
// Currently there is no fallback for profiling i386, since it's not useful.
static _Thread_local NSInteger tls_callDepth;
if (tls_callDepth++ == 0) {
ASSignpostStart(ASSignpostCalculateLayout);
}
#endif
ASSizeRange styleAndParentSize = ASLayoutElementSizeResolve(self.style.size, parentSize);
const ASSizeRange resolvedRange = ASSizeRangeIntersect(constrainedSize, styleAndParentSize);
ASLayout *result = [self calculateLayoutThatFits:resolvedRange];
as_log_verbose(ASLayoutLog(), "Calculated layout %@", result);
#if AS_KDEBUG_ENABLE
if (--tls_callDepth == 0) {
ASSignpostEnd(ASSignpostCalculateLayout);
}
#endif
return result;
}
calculateLayoutThatFits
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize
{
__ASDisplayNodeCheckForLayoutMethodOverrides;
switch (self.layoutEngineType) {
case ASLayoutEngineTypeLayoutSpec:
return [self calculateLayoutLayoutSpec:constrainedSize];
#if YOGA
case ASLayoutEngineTypeYoga:
return [self calculateLayoutYoga:constrainedSize];
#endif
// If YOGA is not defined but for some reason the layout type engine is Yoga
// we explicitly fallthrough here
default:
break;
}
// If this case is reached a layout type engine was defined for a node that is currently
// not supported.
ASDisplayNodeAssert(NO, @"No layout type determined");
return nil;
}
layout
1
2
3
4
5
6
7
8
9
10
- (void)layout
{
// Hook for subclasses
ASDisplayNodeAssertMainThread();
// ASAssertUnlocked(__instanceLock__);
ASDisplayNodeAssertTrue(self.isNodeLoaded);
[self enumerateInterfaceStateDelegates:^(id<ASInterfaceStateDelegate> del) {
[del nodeDidLayout];
}];
}
_layoutTransitionMeasurementDidFinish
1
2
3
4
- (void)_layoutTransitionMeasurementDidFinish
{
// Hook for subclasses - No-Op in ASDisplayNode
}
1
2
3
4
5
6
7
8
9
10
- (void)transitionContext:(_ASTransitionContext *)context didComplete:(BOOL)didComplete
{
ASDisplayNodeAssertMainThread();
[self didCompleteLayoutTransition:context];
_pendingLayoutTransitionContext = nil;
[self _pendingLayoutTransitionDidComplete];
}