-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Conversation
I know this diff is huge, and I attempted to decompose it into smaller updates but to get the correct pager behavior, all of these changes were necessary (excluding e.g. adding the view controller into node debugDescription which was just for fun and seems very low-risk). |
[self performBatchAnimated:YES updates:^{ | ||
[_dataController relayoutAllNodes]; | ||
} completion:nil]; | ||
[_dataController relayoutAllNodes]; |
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.
So much clearer.
} | ||
|
||
CGRect bounds = self.collectionView.bounds; | ||
CGRect rect = CGRectMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds), 1, 1); |
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.
Probably doesn't matter, but should this possibly be CGRectMake(CGRectGetMidX(bounds) - 0.5, CGRectGetMidY(bounds) - 0.5, 1, 1);
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.
I assume it doesn't because the pager should have cells that fill the view?
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.
Right – "government work" level precision is enough here 🏗
* have automaticallyAdjustsScrollViewInsets=NO. | ||
* | ||
* If this property is NO, but your view controller has automaticallyAdjustsScrollViewInsets=YES, | ||
* the pager node will set the property to NO and log a warning message. In the future, |
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.
This isn't 100% clear to me. It will set the property on the view controller to NO? Will it leave the pageNode property NO? Or, will it actually set the pagerNode property to YES?
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.
It will leave the pager property (as NO) but it'll automatically set NO on the view controller (for backwards compatibility) and log a message that it did so. In the future, we want users to be responsible for configuring their own view controllers, so we'll just log the message.
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.
Maybe just a slight adjustment to your comment then: If this property is NO, but your view controller has automaticallyAdjustsScrollViewInsets=YES, the pager node will set the property **on the view controller** to NO and log a warning message.
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.
But without the stars :)
[super didEnterVisibleState]; | ||
|
||
// Check that our view controller does not automatically set our content insets | ||
// It would be better to have a -didEnterHierarchy hook to put this in, but |
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.
Will willEnterHierarchy
not suffice?
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.
No unfortunately, because we're not yet in the hierarchy =(
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.
Interesting, the isInHierarchy flag is set before willEnterHierarchy is called…
ASDisplayNodeAssertMainThread(); | ||
|
||
for (UIResponder *responder in [self asdk_responderChainEnumerator]) { | ||
UIViewController *vc = ASDynamicCast(responder, UIViewController); |
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.
Is this documented behavior? A responder will have it's viewController in the responder chain prior to any other possible view controllers at all times? If not, maybe a comment indicating it's been tested to be true in practice? If so a link would be awesome :)
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.
Hmm I'll leave the link out because the best I could do is a general link to an overview of the responder chain. But responder chain always goes aView -> aView.superview -> aView.superview.viewController -> aView.superview.viewController.view.superview
etc, which is documented.
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.
👍
@@ -21,9 +21,9 @@ | |||
|
|||
@implementation PageNode | |||
|
|||
- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize | |||
- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize |
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.
@note Subclasses that override are committed to manual layout. Therefore, -layout: must be overriden to layout all subnodes or subviews.
Not needed in this case?
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.
Right because we have no subnodes.
Resolves #2974 and other major pager node rotation/content inset issues.
ASCollectionView.zeroContentInsets
.ASPagerNode
to "undo" the effects ofUIViewController.automaticallyAdjustsScrollViewInsets
.contentInsets = .zero
intolayoutSubviews
, after[super layoutSubviews]
contentInsets
is thrashing around constantly.contentOffset
during its insets adjustment, which we didn't account for.ASPagerNode.allowsAutomaticInsetsAdjustment
.NO
since you virtually NEVER want UIVC to adjust pager node insets.NO
, finds the owning view controller of the pager and setsautomaticallyAdjustsScrollViewInsets=NO
, and logs a message.allowsAutomaticInsetsAdjustment=YES
on their pager node.-[UIResponder asdk_associatedViewController]
that safely travels up the responder chain and finds the nearest view controller. This is used above, and it may very well be handy for users especially when debugging. I also put the view controller in the node's-debugDescription
for fun. I could have left it out to keep this diff smaller.ASResponderChainEnumerator
that is used in implementing above, and may come in handy in other places later.ASPagerFlowLayout.currentIndexPath
withASPagerFlowLayout.currentCellNode
so that we can stay pointing at the same node across inserts/deletes.ASPagerFlowLayout
use-shouldInvalidateLayoutForBoundsChange:
– which is like theUICollectionViewLayout
version ofscrollViewDidScroll:
– to update itscurrentIndexPath
, rather than usingtargetContentOffsetForProposedContentOffset:withScrollingVelocity:
, which is not called during programmatic scrolls.performBatchUpdates:
that we placed around_relayoutAllNodes
. The stated reason for the batch updates was to get the relayout into the data controller's transaction pipeline, but it already goes in that pipeline internally, and we don't need to submit an empty update to trigger a layout invalidation, since we're already manually invalidating the layout on the next line. This avoids triggeringUICollectionViewLayout.targetContentOffsetForProposedContentOffset:
needlessly, which happens on every collection view update, even empty ones.ASPagerFlowLayout.m
.In short:
Before:
After:
Note the flashing may look ugly here, but it's intentionally added by flow layout because in a real app, the layout transition is usually going to be bad.