Skip to content

Commit 5558c5f

Browse files
Fabio Carballofacebook-github-bot
Fabio Carballo
authored andcommitted
Propagate visible bounds change if media header is enabled in Tall Post
Summary: This is part of a stack whose goal is to enable the rendering of the header using Litho in Tall Feed Posts. This integration is different than usual because the `LithoView` is nested inside an XML. For that reason we had to propagate identify movements in the host view and propagate the visibility down (this is the general idea): {F1159082704} Reviewed By: adityasharat Differential Revision: D51559814 fbshipit-source-id: 190a48024f5300412b70c7693c8cf79105e6c39f
1 parent 894a555 commit 5558c5f

File tree

2 files changed

+76
-3
lines changed

2 files changed

+76
-3
lines changed

litho-core/src/main/java/com/facebook/litho/BaseMountingView.java

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -698,17 +698,78 @@ void performIncrementalMountForVisibleBoundsChange() {
698698
// Per ComponentTree visible area. Because BaseMountingViews can be nested and mounted
699699
// not in "depth order", this variable cannot be static.
700700
final Rect currentVisibleArea = new Rect();
701-
final boolean hasNonEmptyVisibleRect = getLocalVisibleRect(currentVisibleArea);
701+
final boolean areBoundsVisible = getLocalVisibleRect(currentVisibleArea);
702702

703-
if (hasNonEmptyVisibleRect
703+
if (areBoundsVisible
704704
|| hasComponentsExcludedFromIncrementalMount(getCurrentLayoutState())
705705
// It might not be yet visible but animating from 0 height/width in which case we still
706706
// need to mount them to trigger animation.
707-
|| animatingRootBoundsFromZero(currentVisibleArea)) {
707+
|| animatingRootBoundsFromZero(currentVisibleArea)
708+
|| hasBecomeInvisible()) {
708709
mountComponent(currentVisibleArea, true);
709710
}
710711
}
711712

713+
/**
714+
* This is used to detect an edge case of using Litho in a nested scenario. You can imagine a a
715+
* host XML, which takes a LithoView on top.
716+
*
717+
* <p>As we scroll the LithoView out of the screen, we will process incremental mount correctly
718+
* until the last visible pixel.
719+
*
720+
* <pre>
721+
* |________________________| top: 0
722+
* || ||
723+
* || Litho View ||
724+
* ||______________________|| bottom: 156
725+
* | |
726+
* | |
727+
* | Remaining Host |
728+
* | |
729+
* |_______________________ |
730+
* </pre>
731+
*
732+
* However, once the LithoView goes off the screen but the remaining host is still visible, the
733+
* LithoView rect coordinates become negative:
734+
*
735+
* <pre>
736+
* |________________________| top: -156
737+
* || ||
738+
* || Litho View ||
739+
* ||______________________|| bottom: 0
740+
*
741+
* invisible
742+
* - - - - - - - - - - - - - - - - - - - - - -
743+
* visible
744+
* |_______________________ |
745+
* | |
746+
* | Remaining Host |
747+
* | |
748+
* |_______________________ |
749+
* </pre>
750+
*
751+
* Therefore, the rect is considered not visible, and in normal conditions we wouldn't process an
752+
* extra pass of incremental mount.
753+
*
754+
* <p>We use this check to understand if in the last IM pass, the rect was visible, and that now
755+
* is not. If that is the case, we will do an extra pass of IM to guarantee that the visibility
756+
* outputs are processed and any onInvisible callback is delivered.
757+
*/
758+
private boolean hasBecomeInvisible() {
759+
ComponentsConfiguration configuration = getConfiguration();
760+
boolean shouldNotifyVisibleBoundsChangeWhenNestedLithoViewBecomesInvisible =
761+
configuration != null
762+
&& configuration.shouldNotifyVisibleBoundsChangeWhenNestedLithoViewBecomesInvisible;
763+
764+
return shouldNotifyVisibleBoundsChangeWhenNestedLithoViewBecomesInvisible
765+
&& mPreviousMountVisibleRectBounds.bottom >= 0
766+
&& mPreviousMountVisibleRectBounds.top >= 0
767+
&& mPreviousMountVisibleRectBounds.height() > 0
768+
&& mPreviousMountVisibleRectBounds.left >= 0
769+
&& mPreviousMountVisibleRectBounds.right >= 0
770+
&& mPreviousMountVisibleRectBounds.width() > 0;
771+
}
772+
712773
private boolean animatingRootBoundsFromZero(Rect currentVisibleArea) {
713774
final TreeMountInfo mountInfo = getMountInfo();
714775
final boolean hasMounted = mountInfo != null && mountInfo.hasMounted;

litho-core/src/main/java/com/facebook/litho/config/ComponentsConfiguration.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ internal constructor(
5252
@JvmField val nestedPreallocationEnabled: Boolean = false,
5353
val useNonRebindingEventHandlers: Boolean = false,
5454
internal val shouldDisableBgFgOutputs: Boolean = false,
55+
/**
56+
* We have detected a scenario where we don't process visibility bounds change if the
57+
* localVisibleRect goes of the viewport and a LithoView is nested on an Host that is still
58+
* visible.
59+
*
60+
* This option attempts to tackle this issue by attempting to process an extra pass of IM if we
61+
* detect the Rect became invisible.
62+
*
63+
* Check {@code BaseMountingView#isPreviousRectVisibleAndCurrentInvisible} to get more context.
64+
*/
65+
@JvmField
66+
val shouldNotifyVisibleBoundsChangeWhenNestedLithoViewBecomesInvisible: Boolean = false,
5567
) {
5668

5769
val shouldAddRootHostViewOrDisableBgFgOutputs: Boolean =

0 commit comments

Comments
 (0)