-
Notifications
You must be signed in to change notification settings - Fork 2.2k
[ASDisplayNode] Add automatic measurement before layout #1725
Changes from all commits
1e800af
2ef07ce
52fb99e
923b3b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,8 +53,11 @@ - (void)_staticInitialize; | |
|
|
||
| @end | ||
|
|
||
| //#define LOG(...) NSLog(__VA_ARGS__) | ||
| #define LOG(...) | ||
| #if ASDisplayNodeLoggingEnabled | ||
| #define LOG(...) NSLog(__VA_ARGS__) | ||
| #else | ||
| #define LOG(...) | ||
| #endif | ||
|
|
||
| // Conditionally time these scopes to our debug ivars (only exist in debug/profile builds) | ||
| #if TIME_DISPLAYNODE_OPS | ||
|
|
@@ -880,7 +883,7 @@ - (BOOL)_shouldAbortTransitionWithID:(int32_t)transitionID | |
|
|
||
| - (void)animateLayoutTransition:(id<ASContextTransitioning>)context | ||
| { | ||
| [self __layoutSublayouts]; | ||
| [self __layoutSubnodes]; | ||
| [context completeTransition:YES]; | ||
| } | ||
|
|
||
|
|
@@ -1114,26 +1117,61 @@ - (void)__layout | |
| ASDisplayNodeAssertMainThread(); | ||
| ASDN::MutexLocker l(_propertyLock); | ||
| CGRect bounds = self.bounds; | ||
|
|
||
| [self measureNodeWithBoundsIfNecessary:bounds]; | ||
|
|
||
| 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 | ||
| // measureWithSizeRange: on subnodes to assert. | ||
| return; | ||
| } | ||
|
|
||
| // Handle placeholder layer creation in case the size of the node changed after the initial placeholder layer | ||
| // was created | ||
| if ([self _shouldHavePlaceholderLayer]) { | ||
| [self _setupPlaceholderLayerIfNeeded]; | ||
| } | ||
| _placeholderLayer.frame = bounds; | ||
|
|
||
| [self layout]; | ||
| [self layoutDidFinish]; | ||
| } | ||
|
|
||
| - (void)measureNodeWithBoundsIfNecessary:(CGRect)bounds | ||
| { | ||
| // Normally measure will be called before layout occurs. If this doesn't happen, nothing is going to call it at all. | ||
| // We simply call measureWithSizeRange: using a size range equal to whatever bounds were provided to that element | ||
| if (self.supernode == nil && !self.supportsRangeManagedInterfaceState && [self _hasDirtyLayout]) { | ||
| if (CGRectEqualToRect(bounds, CGRectZero)) { | ||
| LOG(@"Warning: No size given for node before node was trying to layout itself: %@. Please provide a frame for the node.", self); | ||
| } else { | ||
| [self measureWithSizeRange:ASSizeRangeMake(bounds.size, bounds.size)]; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| - (void)layout | ||
| { | ||
| ASDisplayNodeAssertMainThread(); | ||
|
|
||
| if ([self _hasDirtyLayout]) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't read correctly; is it correct? Shouldn't it be == NO? If the layout is dirty, then we should probably layout our subnodes. Maybe this means _isLayoutCalculated, or _isMeasured
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just moved this method, before the |
||
| return; | ||
| } | ||
|
|
||
| [self __layoutSubnodes]; | ||
| } | ||
|
|
||
| - (void)__layoutSubnodes | ||
| { | ||
| for (ASLayout *subnodeLayout in _layout.sublayouts) { | ||
| ((ASDisplayNode *)subnodeLayout.layoutableObject).frame = [subnodeLayout frame]; | ||
| } | ||
| } | ||
|
|
||
| - (void)layoutDidFinish | ||
| { | ||
| // Hook for subclasses | ||
| } | ||
|
|
||
| - (CATransform3D)_transformToAncestor:(ASDisplayNode *)ancestor | ||
|
|
@@ -2463,24 +2501,6 @@ - (void)_applyLayout:(ASLayout *)layout layoutTransition:(ASLayoutTransition *)l | |
| [layoutTransition startTransition]; | ||
| } | ||
|
|
||
| - (void)layout | ||
| { | ||
| ASDisplayNodeAssertMainThread(); | ||
|
|
||
| if ([self _hasDirtyLayout]) { | ||
| return; | ||
| } | ||
|
|
||
| [self __layoutSublayouts]; | ||
| } | ||
|
|
||
| - (void)__layoutSublayouts | ||
| { | ||
| for (ASLayout *subnodeLayout in _layout.sublayouts) { | ||
| ((ASDisplayNode *)subnodeLayout.layoutableObject).frame = [subnodeLayout frame]; | ||
| } | ||
| } | ||
|
|
||
| - (void)displayWillStart | ||
| { | ||
| ASDisplayNodeAssertMainThread(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,8 +14,7 @@ | |
| // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| // | ||
| #import <AsyncDisplayKit/AsyncDisplayKit.h> | ||
| #import <AsyncDisplayKit/ASVideoNode.h> | ||
| #import <UIKit/UIKit.h> | ||
|
|
||
| @interface ViewController : UIViewController | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting. Technically this should be an ASViewController, but of course as-is it makes for a useful test case for this...although a bit of a "secret" purpose / functionality!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree, but we need that for testing purposes. |
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@maicki what about ASViewController? I think there is a way to override the constrainedSize, but the .node has no supernode, is not range managed, etc. This may be handled by _hasDirtyLayout, not sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably want to grab the lock here, at least while checking these three properties. If we don't, the value of one or more could change as the condition is being evaluated... There is also locking overhead in each method as it is re-acquired.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@appleguy In ASViewController we pass in the overwritten constrained size in
measureWithSizeRange:so this will calling through to the measure method and dirty layout is falseWill add acquiring a lock for
supportsRangeManagedInterfaceStateand check for has dirty layout. In[self supernode]we already grab a lock