From 57d66c1e44a676d5aae0255536b5eb4e52a3e326 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Wed, 12 Oct 2022 23:40:34 -0400 Subject: [PATCH] Add fabric support for maintainVisibleContentPosition on Android --- .../react/animated/NativeAnimatedModule.java | 10 +++++++ .../react/bridge/UIManagerListener.java | 27 +++++++++++++++++-- .../react/fabric/FabricUIManager.java | 14 ++++++++++ .../fabric/mounting/MountItemDispatcher.java | 7 +++++ .../MaintainVisibleScrollPositionHelper.java | 19 +++++++++++++ 5 files changed, 75 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java index 1c8f94d831a476..973c552d8169dc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java @@ -298,6 +298,16 @@ public void didScheduleMountItems(UIManager uiManager) { mCurrentFrameNumber++; } + @Override + public void willMountItems(UIManager uiManager) { + // noop + } + + @Override + public void didMountItems(UIManager uiManager) { + // noop + } + // For FabricUIManager only @Override @UiThread diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManagerListener.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManagerListener.java index 984bcf15848ee8..72837cbc2e6b28 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManagerListener.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManagerListener.java @@ -12,10 +12,33 @@ public interface UIManagerListener { /** * Called right before view updates are dispatched at the end of a batch. This is useful if a * module needs to add UIBlocks to the queue before it is flushed. + * + * This is called by Paper only. */ void willDispatchViewUpdates(UIManager uiManager); - /* Called right after view updates are dispatched for a frame. */ + /** + * Called on UIThread right before view updates are executed. + * + * This is called by Fabric only. + */ + void willMountItems(UIManager uiManager); + /** + * Called on UIThread right after view updates are executed. + * + * This is called by Fabric only. + */ + void didMountItems(UIManager uiManager); + /** + * Called on UIThread right after view updates are dispatched for a frame. Note that this will be called + * for every frame even if there are no updates. + * + * This is called by Fabric only. + */ void didDispatchMountItems(UIManager uiManager); - /* Called right after scheduleMountItems is called in Fabric, after a new tree is committed. */ + /** + * Called right after scheduleMountItems is called in Fabric, after a new tree is committed. + * + * This is called by Fabric only. + */ void didScheduleMountItems(UIManager uiManager); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index e0947264fd959a..f8f11e8578e2fd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -1202,6 +1202,20 @@ public Map getPerformanceCounters() { } private class MountItemDispatchListener implements MountItemDispatcher.ItemDispatchListener { + @Override + public void willMountItems() { + for (UIManagerListener listener : mListeners) { + listener.willMountItems(FabricUIManager.this); + } + } + + @Override + public void didMountItems() { + for (UIManagerListener listener : mListeners) { + listener.didMountItems(FabricUIManager.this); + } + } + @Override public void didDispatchMountItems() { for (UIManagerListener listener : mListeners) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java index d6cf5e62b37b34..e4af88d6598eab 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java @@ -193,6 +193,8 @@ private boolean dispatchMountItems() { return false; } + mItemDispatchListener.willMountItems(); + // As an optimization, execute all ViewCommands first // This should be: // 1) Performant: ViewCommands are often a replacement for SetNativeProps, which we've always @@ -299,6 +301,9 @@ private boolean dispatchMountItems() { } mBatchedExecutionTime += SystemClock.uptimeMillis() - batchedExecutionStartTime; } + + mItemDispatchListener.didMountItems(); + Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); return true; @@ -415,6 +420,8 @@ private static void printMountItem(MountItem mountItem, String prefix) { } public interface ItemDispatchListener { + void willMountItems(); + void didMountItems(); void didDispatchMountItems(); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.java index 6ce4d8b23d2bbf..f76c432b59047c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.java @@ -18,6 +18,7 @@ import com.facebook.react.bridge.UIManagerListener; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.uimanager.UIManagerHelper; +import com.facebook.react.uimanager.common.UIManagerType; import com.facebook.react.uimanager.common.ViewUtil; import com.facebook.react.views.scroll.ReactScrollViewHelper.HasSmoothScroll; import com.facebook.react.views.view.ReactViewGroup; @@ -89,6 +90,14 @@ public void stop() { * been updated. */ public void updateScrollPosition() { + // On Fabric this will be called internally in `didMountItems`. + if (ViewUtil.getUIManagerType(mScrollView.getId()) == UIManagerType.FABRIC) { + return; + } + updateScrollPositionInternal(); + } + + private void updateScrollPositionInternal() { if (mConfig == null || mFirstVisibleView == null || mPrevFirstVisibleFrame == null) { return; } @@ -169,6 +178,16 @@ public void run() { }); } + @Override + public void willMountItems(UIManager uiManager) { + computeTargetView(); + } + + @Override + public void didMountItems(UIManager uiManager) { + updateScrollPositionInternal(); + } + @Override public void didDispatchMountItems(UIManager uiManager) { // noop