diff --git a/src/FlashListProps.ts b/src/FlashListProps.ts index 9f03ee7dc..ce8b00701 100644 --- a/src/FlashListProps.ts +++ b/src/FlashListProps.ts @@ -344,4 +344,5 @@ export interface FlashListProps extends ScrollViewProps { * can consider the visible area of the bottom sheet in its calculations. */ bottomViewabilityInsetRef?: React.MutableRefObject; + topViewabilityInsetRef?: React.MutableRefObject; } diff --git a/src/__tests__/ViewabilityHelper.test.ts b/src/__tests__/ViewabilityHelper.test.ts index 52ac04a29..64c1da0ff 100644 --- a/src/__tests__/ViewabilityHelper.test.ts +++ b/src/__tests__/ViewabilityHelper.test.ts @@ -257,6 +257,7 @@ describe("ViewabilityHelper", () => { horizontal, scrollOffset, bottomViewabilityInset, + topViewabilityInset, listSize, getLayout, runAllTimers, @@ -265,6 +266,7 @@ describe("ViewabilityHelper", () => { horizontal?: boolean; scrollOffset?: number; bottomViewabilityInset?: number; + topViewabilityInset?: number; listSize?: Dimension; getLayout?: (index: number) => Layout | undefined; runAllTimers?: boolean; @@ -273,6 +275,7 @@ describe("ViewabilityHelper", () => { horizontal ?? false, scrollOffset ?? 0, bottomViewabilityInset ?? 0, + topViewabilityInset ?? 0, listSize ?? { height: 300, width: 300 }, getLayout ?? ((index) => { diff --git a/src/viewability/ViewabilityHelper.ts b/src/viewability/ViewabilityHelper.ts index d432b7900..e976f159a 100644 --- a/src/viewability/ViewabilityHelper.ts +++ b/src/viewability/ViewabilityHelper.ts @@ -49,6 +49,7 @@ class ViewabilityHelper { horizontal: boolean, scrollOffset: number, bottomViewabilityInset: number, + topViewabilityInset: number, listSize: Dimension, getLayout: (index: number) => Layout | undefined, viewableIndices?: number[] @@ -78,6 +79,7 @@ class ViewabilityHelper { horizontal, scrollOffset, bottomViewabilityInset, + topViewabilityInset, listSize, this.viewabilityConfig?.viewAreaCoveragePercentThreshold, this.viewabilityConfig?.itemVisiblePercentThreshold, @@ -127,6 +129,7 @@ class ViewabilityHelper { horizontal: boolean, scrollOffset: number, bottomViewabilityInset: number, + topViewabilityInset: number, listSize: Dimension, viewAreaCoveragePercentThreshold: number | null | undefined, itemVisiblePercentThreshold: number | null | undefined, @@ -139,10 +142,11 @@ class ViewabilityHelper { const itemTop = (horizontal ? itemLayout.x : itemLayout.y) - scrollOffset; const itemSize = horizontal ? itemLayout.width : itemLayout.height; const listMainSize = horizontal - ? listSize.width - : listSize.height - bottomViewabilityInset; + ? listSize.width - topViewabilityInset - bottomViewabilityInset + : listSize.height - topViewabilityInset - bottomViewabilityInset; const pixelsVisible = - Math.min(itemTop + itemSize, listMainSize) - Math.max(itemTop, 0); + Math.min(itemTop + itemSize, listMainSize + topViewabilityInset) - + Math.max(itemTop, 0); // Always consider item fully viewable if it is fully visible, regardless of the `viewAreaCoveragePercentThreshold` // Account for floating point imprecision. @@ -157,7 +161,7 @@ class ViewabilityHelper { viewAreaCoveragePercentThreshold !== null && viewAreaCoveragePercentThreshold !== undefined; const percent = viewAreaMode - ? pixelsVisible / listMainSize + ? pixelsVisible / (listMainSize + topViewabilityInset) : pixelsVisible / itemSize; const viewableAreaPercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold * 0.01 diff --git a/src/viewability/ViewabilityManager.ts b/src/viewability/ViewabilityManager.ts index cc23bfe9b..b03a0e9b0 100644 --- a/src/viewability/ViewabilityManager.ts +++ b/src/viewability/ViewabilityManager.ts @@ -79,12 +79,15 @@ export default class ViewabilityManager { const bottomViewabilityInset = this.flashListRef.props.bottomViewabilityInsetRef?.current ?? 0; + const topViewabilityInset = + this.flashListRef.props.topViewabilityInsetRef?.current ?? 0; this.viewabilityHelpers.forEach((viewabilityHelper) => { viewabilityHelper.updateViewableItems( this.flashListRef.props.horizontal ?? false, scrollOffset, bottomViewabilityInset, + topViewabilityInset, listSize, (index: number) => this.flashListRef.recyclerlistview_unsafe?.getLayout(index),