- Support internal relayout, that is a relayout caused by internal layout changes, like subnodes re-arrangement and/or subnodes' size change. The constrained size applied to root node is unchanged.

- Update Kittens example to show how internal relayout is done.
This commit is contained in:
Huy Nguyen
2015-08-02 09:20:46 +03:00
parent 16ed66c3a1
commit 56768a837a
7 changed files with 67 additions and 5 deletions

View File

@@ -506,7 +506,18 @@ typedef CALayer *(^ASDisplayNodeLayerBlock)();
@interface ASDisplayNode (UIViewBridge)
- (void)setNeedsDisplay; // Marks the view as needing display. Convenience for use whether view is created or not, or from a background thread.
- (void)setNeedsLayout; // Marks the view as needing layout. Convenience for use whether view is created or not, or from a background thread.
/**
* Marks the view as needing layout. Convenience for use whether view is created or not, or from a background thread.
*
* If this node was measured, calling this method triggers an internal relayout: the calculated layout is invalidated,
* and the supernode is notified or (if this node is the root one) a full measurement pass is executed using the old constrained size.
*
* Note: If the relayout causes a change in size of the root node that is attached to a container view
* (table or collection view, for example), the container view must be notified to redraw.
* In case of table or collection view, calling -beginUpdates and -endUpdates is enough.
*/
- (void)setNeedsLayout;
@property (atomic, retain) id contents; // default=nil
@property (atomic, assign) BOOL clipsToBounds; // default==NO

View File

@@ -560,6 +560,28 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
[[self asyncLayer] displayImmediately];
}
- (void)__setNeedsLayout
{
ASDisplayNodeAssertThreadAffinity(self);
ASDN::MutexLocker l(_propertyLock);
if (!_flags.isMeasured) {
return;
}
ASSizeRange oldConstrainedSize = _constrainedSize;
[self invalidateCalculatedLayout];
if (_supernode) {
// Cause supernode's layout to be invalidated
[_supernode setNeedsLayout];
} else {
// This is the root node. Trigger a full measurement pass on *current* thread. Old constrained size is re-used.
[self measureWithSizeRange:oldConstrainedSize];
self.frame = CGRectMake(0.0f, 0.0f, _layout.size.width, _layout.size.height);
}
}
// These private methods ensure that subclasses are not required to call super in order for _renderingSubnodes to be properly managed.
- (void)__layout

View File

@@ -174,6 +174,7 @@
- (void)setNeedsLayout
{
_bridge_prologue;
[self __setNeedsLayout];
_messageToViewOrLayer(setNeedsLayout);
}

View File

@@ -121,6 +121,7 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) {
// Core implementation of -measureWithSizeRange:. Must be called with _propertyLock held.
- (ASLayout *)__measureWithSizeRange:(ASSizeRange)constrainedSize;
- (void)__setNeedsLayout;
- (void)__layout;
- (void)__setSupernode:(ASDisplayNode *)supernode;

View File

@@ -19,4 +19,6 @@
- (instancetype)initWithKittenOfSize:(CGSize)size;
- (void)toggleImageEnlargement;
@end

View File

@@ -29,6 +29,8 @@ static const CGFloat kInnerPadding = 10.0f;
ASNetworkImageNode *_imageNode;
ASTextNode *_textNode;
ASDisplayNode *_divider;
BOOL _isImageEnlarged;
BOOL _isNodesSwapped;
}
@end
@@ -84,6 +86,7 @@ static const CGFloat kInnerPadding = 10.0f;
(NSInteger)roundl(_kittenSize.width),
(NSInteger)roundl(_kittenSize.height)]];
// _imageNode.contentMode = UIViewContentModeCenter;
[_imageNode addTarget:self action:@selector(toggleNodesSwap) forControlEvents:ASControlNodeEventTouchUpInside];
[self addSubnode:_imageNode];
// lorem ipsum text, plus some nice styling
@@ -132,7 +135,7 @@ static const CGFloat kInnerPadding = 10.0f;
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
{
ASRatioLayoutSpec *imagePlaceholder = [ASRatioLayoutSpec newWithRatio:1.0 child:_imageNode];
imagePlaceholder.flexBasis = ASRelativeDimensionMakeWithPoints(kImageSize);
imagePlaceholder.flexBasis = ASRelativeDimensionMakeWithPoints(kImageSize * (!_isImageEnlarged ? 1 : 2));
_textNode.flexShrink = YES;
@@ -145,7 +148,7 @@ static const CGFloat kInnerPadding = 10.0f;
.direction = ASStackLayoutDirectionHorizontal,
.spacing = kInnerPadding
}
children:@[imagePlaceholder, _textNode]]];
children:!_isNodesSwapped ? @[imagePlaceholder, _textNode] : @[_textNode, imagePlaceholder]]];
}
// With box model, you don't need to override this method, unless you want to add custom logic.
@@ -181,4 +184,16 @@ static const CGFloat kInnerPadding = 10.0f;
}
#endif
- (void)toggleImageEnlargement
{
_isImageEnlarged = !_isImageEnlarged;
[self setNeedsLayout];
}
- (void)toggleNodesSwap
{
_isNodesSwapped = !_isNodesSwapped;
[self setNeedsLayout];
}
@end

View File

@@ -102,6 +102,16 @@ static const NSInteger kMaxLitterSize = 100; // max number of kitten cell
#pragma mark -
#pragma mark ASTableView.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[_tableView deselectRowAtIndexPath:indexPath animated:YES];
[_tableView beginUpdates];
// Assume only kitten nodes are selectable (see -tableView:shouldHighlightRowAtIndexPath:).
KittenNode *node = (KittenNode *)[_tableView nodeForRowAtIndexPath:indexPath];
[node toggleImageEnlargement];
[_tableView endUpdates];
}
- (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath
{
// special-case the first row
@@ -123,8 +133,8 @@ static const NSInteger kMaxLitterSize = 100; // max number of kitten cell
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath
{
// disable row selection
return NO;
// Enable selection for kitten nodes
return indexPath.section != 0 || indexPath.row != 0;
}
- (void)tableViewLockDataSource:(ASTableView *)tableView