Skip to content

Commit

Permalink
Ensure an ASM enabled node applies its pending layout when enters pre…
Browse files Browse the repository at this point in the history
…load state (TextureGroup#706)

This makes sure subnodes are inserted and start preloading right away, instead of waiting until the next layout pass of the supernode. Fixes TextureGroup#693.
  • Loading branch information
nguyenhuy authored and bernieperez committed Apr 25, 2018
1 parent 0d817d1 commit 10e46c1
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- [ASScrollNode] Ensure the node respects the given size range while calculating its layout. [#637](https://github.com/TextureGroup/Texture/pull/637) [Huy Nguyen](https://github.com/nguyenhuy)
- [ASScrollNode] Invalidate the node's calculated layout if its scrollable directions changed. Also add unit tests for the class. [#637](https://github.com/TextureGroup/Texture/pull/637) [Huy Nguyen](https://github.com/nguyenhuy)
- Add new unit testing to the layout engine. [Adlai Holler](https://github.com/Adlai-Holler) [#424](https://github.com/TextureGroup/Texture/pull/424)
- [Automatic Subnode Management] Nodes with ASM enabled now insert/delete their subnodes as soon as they enter preload state, so the subnodes can preload too. [Huy Nguyen](https://github.com/nguyenhuy) [#706](https://github.com/TextureGroup/Texture/pull/706)

## 2.6
- [Xcode 9] Updated to require Xcode 9 (to fix warnings) [Garrett Moon](https://github.com/garrettmoon)
Expand Down
14 changes: 14 additions & 0 deletions Source/ASDisplayNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3079,6 +3079,20 @@ - (void)didEnterPreloadState
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssertLockUnownedByCurrentThread(__instanceLock__);

if (self.automaticallyManagesSubnodes) {
// Tell the node to apply its applicable pending layout, if any, so that its subnodes are inserted/deleted
// and start preloading right away.
//
// If this node has an up-to-date layout (and subnodes), calling layoutIfNeeded will be fast.
//
// If this node doesn't have a calculated or pending layout that fits its current bounds, a measurement pass will occur
// (see __layout and _u_measureNodeWithBoundsIfNecessary:).
// This scenario should be uncommon, and running a measurement pass here is a fine trade-off because preloading
// any time after this point would be late.
[self layoutIfNeeded];
}

[_interfaceStateDelegate didEnterPreloadState];
}

Expand Down
44 changes: 42 additions & 2 deletions Tests/ASDisplayNodeImplicitHierarchyTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// ASDisplayNodeImplicitHierarchyTests.m
// Texture
//
// Created by Levi McCallum on 2/1/16.
//
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
Expand All @@ -20,6 +18,7 @@
#import <XCTest/XCTest.h>

#import <AsyncDisplayKit/AsyncDisplayKit.h>
#import <AsyncDisplayKit/ASDisplayNode+FrameworkPrivate.h>
#import "ASDisplayNodeTestsHelper.h"

@interface ASSpecTestDisplayNode : ASDisplayNode
Expand Down Expand Up @@ -101,6 +100,47 @@ - (void)testInitialNodeInsertionWithOrdering
XCTAssertEqual(node.subnodes[4], node5);
}

- (void)testInitialNodeInsertionWhenEnterPreloadState
{
static CGSize kSize = {100, 100};

static NSInteger subnodeCount = 5;
NSMutableArray<ASDisplayNode *> *subnodes = [NSMutableArray arrayWithCapacity:subnodeCount];
for (NSInteger i = 0; i < subnodeCount; i++) {
ASDisplayNode *subnode = [[ASDisplayNode alloc] init];
// As we will involve a stack spec we have to give the nodes an intrinsic content size
subnode.style.preferredSize = kSize;
[subnodes addObject:subnode];
}

ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
node.automaticallyManagesSubnodes = YES;
node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize) {
ASAbsoluteLayoutSpec *absoluteLayout = [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[subnodes[3]]];

ASStackLayoutSpec *stack1 = [[ASStackLayoutSpec alloc] init];
[stack1 setChildren:@[subnodes[0], subnodes[1]]];

ASStackLayoutSpec *stack2 = [[ASStackLayoutSpec alloc] init];
[stack2 setChildren:@[subnodes[2], absoluteLayout]];

return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[stack1, stack2, subnodes[4]]];
};

ASDisplayNodeSizeToFitSizeRange(node, ASSizeRangeMake(CGSizeZero, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)));
[node recursivelySetInterfaceState:ASInterfaceStatePreload];

// No premature view allocation
XCTAssertFalse(node.isNodeLoaded);
// Subnodes should be inserted, laid out and entered preload state
XCTAssertTrue([subnodes isEqualToArray:node.subnodes]);
for (NSInteger i = 0; i < subnodeCount; i++) {
ASDisplayNode *subnode = subnodes[i];
XCTAssertTrue(CGSizeEqualToSize(kSize, subnode.bounds.size));
XCTAssertTrue(ASInterfaceStateIncludesPreload(subnode.interfaceState));
}
}

- (void)testCalculatedLayoutHierarchyTransitions
{
static CGSize kSize = {100, 100};
Expand Down

0 comments on commit 10e46c1

Please sign in to comment.