-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Open
Description
What happened?
When using largeTitle: { visible: true }
with a ScrollView
or FlatList
containing a RefreshControl
, the refresh control spinner flickers/jumps during pull-to-refresh on iOS. This creates a poor user experience.
Also the fade transition from big to small is janky.
Note! This works well if largeText is not visible.
Steps to Reproduce
- Create a screen with
largeTitle: { visible: true }
in navigation options - Use a
ScrollView
orFlatList
withRefreshControl
as content - Pull down to refresh on iOS
- Observe flickering/jumping of the refresh control
ScreenRecording_07-29-2025.15-32-01_1.MP4
What was the expected behaviour?
The refresh control should smoothly animate without flickering.
Was it tested on latest react-native-navigation?
- I have tested this issue on the latest react-native-navigation release and it still reproduces.
Help us reproduce this issue!
Code Example
import React, { useState } from 'react'
import {
RefreshControl,
SafeAreaView,
ScrollView,
Text,
View,
} from 'react-native'
import { NavigationFunctionComponent } from 'react-native-navigation'
// Dummy data for demonstration
const DUMMY_ITEMS = Array.from({ length: 20 }, (_, i) => ({
id: i,
title: `Item ${i + 1}`,
description: `This is a description for item ${i + 1}`,
}))
export const DummScreen: NavigationFunctionComponent = () => {
const [refreshing, setRefreshing] = useState(false)
const onRefresh = async () => {
setRefreshing(true)
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 2000))
setRefreshing(false)
}
return (
<SafeAreaView style={{ flex: 1 }}>
<ScrollView
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
contentContainerStyle={{ padding: 16 }}
>
{DUMMY_ITEMS.map((item) => (
<View
key={item.id}
style={{
padding: 16,
marginBottom: 8,
backgroundColor: '#f0f0f0',
borderRadius: 8,
}}
>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>
{item.title}
</Text>
<Text style={{ fontSize: 14, color: '#666', marginTop: 4 }}>
{item.description}
</Text>
</View>
))}
</ScrollView>
</SafeAreaView>
)
}
// Static options following the docs example
ApplicationsScreen.options = {
topBar: {
title: {
text: 'Dummy Screen',
},
largeTitle: {
visible: true, // This causes the flickering issue
},
scrollEdgeAppearance: {
active: true,
noBorder: true,
},
},
}
In what environment did this happen?
Environment
- React Native Navigation version: 8.2.1 (patched)
- React Native version: 0.77.2 (patched)
- Has Fabric (React Native's new rendering system) enabled: yes
- Node version: 20.15.0
- Device model: iPhone 15 Pro
Patches
React native navigation patch
diff --git a/ReactNativeNavigation.podspec b/ReactNativeNavigation.podspec
index 1777dc62b018f884dcee620f9b404ec37f49c683..24eb71637993f5e2fa01673386e1882ca612dd99 100644
--- a/ReactNativeNavigation.podspec
+++ b/ReactNativeNavigation.podspec
@@ -44,7 +44,9 @@ Pod::Spec.new do |s|
# Only expose headers for Swift projects
if swift_project
s.public_header_files = [
- 'lib/ios/RNNAppDelegate.h'
+ 'lib/ios/RNNAppDelegate.h',
+ 'lib/ios/ReactNativeNavigation.h',
+ 'lib/ios/TurboModules/RNNTurboManager.h'
]
end
end
React native patch
diff --git a/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm b/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm
index b796713ed0670a50aa8dddcc32b8732058f0bb47..5142307e8b94faba52cbcc1cdb9556f00f1faa1c 100644
--- a/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm
+++ b/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm
@@ -254,7 +254,9 @@ - (RCTFabricSurface *)createSurfaceWithModuleName:(NSString *)moduleName
surface.surfaceHandler.setDisplayMode(displayMode);
[self _attachSurface:surface];
- [_instance callFunctionOnBufferedRuntimeExecutor:[surface](facebook::jsi::Runtime &_) { [surface start]; }];
+ __weak RCTFabricSurface *weakSurface = surface;
+ // Use the BufferedRuntimeExecutor to start the surface after the main JS bundle was fully executed.
+ [_instance callFunctionOnBufferedRuntimeExecutor:[weakSurface](facebook::jsi::Runtime &_) { [weakSurface start]; }];
return surface;
}
mayconmesquita