Skip to content

Commit 37abba0

Browse files
janicduplessiskelset
authored andcommitted
Add fabric support for maintainVisibleContentPosition on Android (#35994)
Summary: Implement a few missing bits for `maintainVisibleContentPosition` to work with fabric. The main thing needed is to add 2 fabric renderer listener methods to allow to hook into specific parts of the rendering process. We need some code to execute before view updates are executed and after view updates are executed. The current methods that are exposed do not work for this case. `willDispatchViewUpdates` is called from JS thread, and there doesn't seem to be a way to add UI blocks that will be executed at the right time like we do in paper. `didDispatchMountItems` is called for every frame which we don't want and will cause lots of overhead. After that we simply need to call the right methods in the new renderer listener methods. ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: [ANDROID] [ADDED] - Add fabric support for maintainVisibleContentPosition on Android For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> Pull Request resolved: #35994 Test Plan: Tested in RN tester maintainVisibleContentPosition example on Android with fabric enabled. Reviewed By: cipolleschi Differential Revision: D44131763 Pulled By: cortinico fbshipit-source-id: 32c0b5867d460537b18a70d472fd58052da6cf80
1 parent c068efc commit 37abba0

File tree

5 files changed

+77
-2
lines changed

5 files changed

+77
-2
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,16 @@ public void didScheduleMountItems(UIManager uiManager) {
295295
mCurrentFrameNumber++;
296296
}
297297

298+
@Override
299+
public void willMountItems(UIManager uiManager) {
300+
// noop
301+
}
302+
303+
@Override
304+
public void didMountItems(UIManager uiManager) {
305+
// noop
306+
}
307+
298308
// For FabricUIManager only
299309
@Override
300310
@UiThread

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManagerListener.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,33 @@ public interface UIManagerListener {
1212
/**
1313
* Called right before view updates are dispatched at the end of a batch. This is useful if a
1414
* module needs to add UIBlocks to the queue before it is flushed.
15+
*
16+
* <p>This is called by Paper only.
1517
*/
1618
void willDispatchViewUpdates(UIManager uiManager);
17-
/* Called right after view updates are dispatched for a frame. */
19+
/**
20+
* Called on UIThread right before view updates are executed.
21+
*
22+
* <p>This is called by Fabric only.
23+
*/
24+
void willMountItems(UIManager uiManager);
25+
/**
26+
* Called on UIThread right after view updates are executed.
27+
*
28+
* <p>This is called by Fabric only.
29+
*/
30+
void didMountItems(UIManager uiManager);
31+
/**
32+
* Called on UIThread right after view updates are dispatched for a frame. Note that this will be
33+
* called for every frame even if there are no updates.
34+
*
35+
* <p>This is called by Fabric only.
36+
*/
1837
void didDispatchMountItems(UIManager uiManager);
19-
/* Called right after scheduleMountItems is called in Fabric, after a new tree is committed. */
38+
/**
39+
* Called right after scheduleMountItems is called in Fabric, after a new tree is committed.
40+
*
41+
* <p>This is called by Fabric only.
42+
*/
2043
void didScheduleMountItems(UIManager uiManager);
2144
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,20 @@ public Map<String, Long> getPerformanceCounters() {
11711171
}
11721172

11731173
private class MountItemDispatchListener implements MountItemDispatcher.ItemDispatchListener {
1174+
@Override
1175+
public void willMountItems() {
1176+
for (UIManagerListener listener : mListeners) {
1177+
listener.willMountItems(FabricUIManager.this);
1178+
}
1179+
}
1180+
1181+
@Override
1182+
public void didMountItems() {
1183+
for (UIManagerListener listener : mListeners) {
1184+
listener.didMountItems(FabricUIManager.this);
1185+
}
1186+
}
1187+
11741188
@Override
11751189
public void didDispatchMountItems() {
11761190
for (UIManagerListener listener : mListeners) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ private boolean dispatchMountItems() {
193193
return false;
194194
}
195195

196+
mItemDispatchListener.willMountItems();
197+
196198
// As an optimization, execute all ViewCommands first
197199
// This should be:
198200
// 1) Performant: ViewCommands are often a replacement for SetNativeProps, which we've always
@@ -299,6 +301,9 @@ private boolean dispatchMountItems() {
299301
}
300302
mBatchedExecutionTime += SystemClock.uptimeMillis() - batchedExecutionStartTime;
301303
}
304+
305+
mItemDispatchListener.didMountItems();
306+
302307
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
303308

304309
return true;
@@ -415,6 +420,10 @@ private static void printMountItem(MountItem mountItem, String prefix) {
415420
}
416421

417422
public interface ItemDispatchListener {
423+
void willMountItems();
424+
425+
void didMountItems();
426+
418427
void didDispatchMountItems();
419428
}
420429
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.facebook.react.bridge.UIManagerListener;
1919
import com.facebook.react.bridge.UiThreadUtil;
2020
import com.facebook.react.uimanager.UIManagerHelper;
21+
import com.facebook.react.uimanager.common.UIManagerType;
2122
import com.facebook.react.uimanager.common.ViewUtil;
2223
import com.facebook.react.views.scroll.ReactScrollViewHelper.HasSmoothScroll;
2324
import com.facebook.react.views.view.ReactViewGroup;
@@ -89,6 +90,14 @@ public void stop() {
8990
* been updated.
9091
*/
9192
public void updateScrollPosition() {
93+
// On Fabric this will be called internally in `didMountItems`.
94+
if (ViewUtil.getUIManagerType(mScrollView.getId()) == UIManagerType.FABRIC) {
95+
return;
96+
}
97+
updateScrollPositionInternal();
98+
}
99+
100+
private void updateScrollPositionInternal() {
92101
if (mConfig == null || mFirstVisibleView == null || mPrevFirstVisibleFrame == null) {
93102
return;
94103
}
@@ -169,6 +178,16 @@ public void run() {
169178
});
170179
}
171180

181+
@Override
182+
public void willMountItems(UIManager uiManager) {
183+
computeTargetView();
184+
}
185+
186+
@Override
187+
public void didMountItems(UIManager uiManager) {
188+
updateScrollPositionInternal();
189+
}
190+
172191
@Override
173192
public void didDispatchMountItems(UIManager uiManager) {
174193
// noop

0 commit comments

Comments
 (0)