In onLayout, only scroll if the content view is ready

Summary:
ScrollViews don't properly maintain position where they are hidden and shown. There is an edge case where on onLayout for a ScrollView, its content may not have been laid out yet. This happens in some cases when a scroll view is hidden via display: 'none' (resulting in setVisibility(INVISIBLE)). Check that the content view is laid out before attempting a scroll.

Changelog:
[Internal][Fixed] - In onLayout, only scroll if the content view is ready

Reviewed By: sshic

Differential Revision: D42794750

fbshipit-source-id: 654a380bcae306da2704d3e190423c8de125833d
This commit is contained in:
Genki Kondo
2023-01-30 11:55:13 -08:00
committed by Facebook GitHub Bot
parent 47903d0c62
commit 9e65ba2b7b
2 changed files with 22 additions and 16 deletions
@@ -356,14 +356,17 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
mScrollXAfterMeasure = NO_SCROLL_POSITION;
}
// Call with the present values in order to re-layout if necessary
// If a "pending" value has been set, we restore that value.
// That value gets cleared by reactScrollTo.
int scrollToX =
pendingContentOffsetX != UNSET_CONTENT_OFFSET ? pendingContentOffsetX : getScrollX();
int scrollToY =
pendingContentOffsetY != UNSET_CONTENT_OFFSET ? pendingContentOffsetY : getScrollY();
scrollTo(scrollToX, scrollToY);
// Apply pending contentOffset in case it was set before the view was laid out.
if (isContentReady()) {
// If a "pending" content offset value has been set, we restore that value.
// Upon call to scrollTo, the "pending" values will be re-set.
int scrollToX =
pendingContentOffsetX != UNSET_CONTENT_OFFSET ? pendingContentOffsetX : getScrollX();
int scrollToY =
pendingContentOffsetY != UNSET_CONTENT_OFFSET ? pendingContentOffsetY : getScrollY();
scrollTo(scrollToX, scrollToY);
}
ReactScrollViewHelper.emitLayoutEvent(this);
}
@@ -286,14 +286,17 @@ public class ReactScrollView extends ScrollView
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// Call with the present values in order to re-layout if necessary
// If a "pending" content offset value has been set, we restore that value.
// Upon call to scrollTo, the "pending" values will be re-set.
int scrollToX =
pendingContentOffsetX != UNSET_CONTENT_OFFSET ? pendingContentOffsetX : getScrollX();
int scrollToY =
pendingContentOffsetY != UNSET_CONTENT_OFFSET ? pendingContentOffsetY : getScrollY();
scrollTo(scrollToX, scrollToY);
// Apply pending contentOffset in case it was set before the view was laid out.
if (isContentReady()) {
// If a "pending" content offset value has been set, we restore that value.
// Upon call to scrollTo, the "pending" values will be re-set.
int scrollToX =
pendingContentOffsetX != UNSET_CONTENT_OFFSET ? pendingContentOffsetX : getScrollX();
int scrollToY =
pendingContentOffsetY != UNSET_CONTENT_OFFSET ? pendingContentOffsetY : getScrollY();
scrollTo(scrollToX, scrollToY);
}
ReactScrollViewHelper.emitLayoutEvent(this);
}