Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Match interfacestate update sequence to uikit #882

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions Source/ASCollectionView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2273,15 +2273,23 @@ - (void)didMoveToWindow
{
BOOL visible = (self.window != nil);
ASDisplayNode *node = self.collectionNode;
BOOL rangeControllerNeedsUpdate = ![node supportsRangeManagedInterfaceState];;

if (!visible && node.inHierarchy) {
if (rangeControllerNeedsUpdate) {
rangeControllerNeedsUpdate = NO;
// Exit CellNodes first before Collection to match UIKit behaviors (tear down bottom up).
// Although we have not yet cleared the interfaceState's Visible bit (this happens in __exitHierarchy),
// the ASRangeController will get the correct value from -interfaceStateForRangeController:.
[_rangeController updateRanges];
}
[node __exitHierarchy];
}

// Updating the visible node index paths only for not range managed nodes. Range managed nodes will get their
// their update in the layout pass
if (![node supportsRangeManagedInterfaceState]) {
[_rangeController setNeedsUpdate];
[_rangeController updateIfNeeded];
if (rangeControllerNeedsUpdate) {
[_rangeController updateRanges];
}

// When we aren't visible, we will only fetch up to the visible area. Now that we are visible,
Expand Down
14 changes: 11 additions & 3 deletions Source/ASTableView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1907,15 +1907,23 @@ - (void)didMoveToWindow
{
BOOL visible = (self.window != nil);
ASDisplayNode *node = self.tableNode;
BOOL rangeControllerNeedsUpdate = ![node supportsRangeManagedInterfaceState];;

if (!visible && node.inHierarchy) {
if (rangeControllerNeedsUpdate) {
rangeControllerNeedsUpdate = NO;
// Exit CellNodes first before Table to match UIKit behaviors (tear down bottom up).
// Although we have not yet cleared the interfaceState's Visible bit (this happens in __exitHierarchy),
// the ASRangeController will get the correct value from -interfaceStateForRangeController:.
[_rangeController updateRanges];
}
[node __exitHierarchy];
}

// Updating the visible node index paths only for not range managed nodes. Range managed nodes will get their
// their update in the layout pass
if (![node supportsRangeManagedInterfaceState]) {
[_rangeController setNeedsUpdate];
[_rangeController updateIfNeeded];
if (rangeControllerNeedsUpdate) {
[_rangeController updateRanges];
}

// When we aren't visible, we will only fetch up to the visible area. Now that we are visible,
Expand Down
5 changes: 5 additions & 0 deletions Source/Details/ASRangeController.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ AS_SUBCLASSING_RESTRICTED
*/
- (void)updateIfNeeded;

/**
* Force update the ranges immediately.
*/
- (void)updateRanges;

/**
* Add the sized node for `indexPath` as a subview of `contentView`.
*
Expand Down
12 changes: 8 additions & 4 deletions Source/Details/ASRangeController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,16 @@ - (void)setNeedsUpdate
- (void)updateIfNeeded
{
if (_needsRangeUpdate) {
_needsRangeUpdate = NO;

[self _updateVisibleNodeIndexPaths];
[self updateRanges];
}
}

- (void)updateRanges
{
_needsRangeUpdate = NO;
[self _updateVisibleNodeIndexPaths];
}

- (void)updateCurrentRangeWithMode:(ASLayoutRangeMode)rangeMode
{
_preserveCurrentRangeMode = YES;
Expand Down Expand Up @@ -376,7 +380,7 @@ - (void)_updateVisibleNodeIndexPaths
[newVisibleNodes addObject:node];
}
// Skip the many method calls of the recursive operation if the top level cell node already has the right interfaceState.
if (node.interfaceState != interfaceState) {
if (node.pendingInterfaceState != interfaceState) {
Copy link
Contributor Author

@wsdwsd0829 wsdwsd0829 Apr 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will make sure the correct interface exiting order when thrashing happen during push animation (node being pushed will exit - enter - exit hierarchy).
Note the first exit & enter happened in one runloop triggered by CAAnimation inside UIKit.
Before the change: node will exit for first exit call instead of last. End up visible cell node exit, collection exit, other cell node in preload/display exit.
After the change: Collection exit, cell in visible/preload/display exits

#if ASRangeControllerLoggingEnabled
[modifiedIndexPaths addObject:indexPath];
#endif
Expand Down