1
1
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs"
2
+ import { useIsFocused } from "@react-navigation/native"
2
3
import { createNativeStackNavigator } from "@react-navigation/native-stack"
3
- import { useContext , useEffect } from "react"
4
+ import { createContext , useCallback , useContext , useEffect , useRef } from "react"
4
5
import type { NativeScrollEvent , NativeSyntheticEvent } from "react-native"
5
- import { ScrollView , useAnimatedValue } from "react-native"
6
+ import { findNodeHandle , ScrollView , UIManager , useAnimatedValue } from "react-native"
6
7
import { withTiming } from "react-native-reanimated"
7
8
import { useSafeAreaInsets } from "react-native-safe-area-context"
8
9
import { useEventCallback } from "usehooks-ts"
@@ -13,33 +14,29 @@ import { SettingsList } from "@/src/modules/settings/SettingsList"
13
14
import { UserHeaderBanner } from "@/src/modules/settings/UserHeaderBanner"
14
15
15
16
const Stack = createNativeStackNavigator ( )
17
+ const OutIsFocused = createContext ( false )
16
18
export default function SettingsX ( ) {
19
+ const isFocused = useIsFocused ( )
20
+
17
21
return (
18
- < Stack . Navigator initialRouteName = "Settings" >
19
- < Stack . Screen name = "Settings" component = { Settings } options = { { headerShown : false } } />
20
- { SettingRoutes ( Stack ) }
21
- </ Stack . Navigator >
22
+ < OutIsFocused . Provider value = { isFocused } >
23
+ < Stack . Navigator initialRouteName = "Settings" >
24
+ < Stack . Screen name = "Settings" component = { Settings } options = { { headerShown : false } } />
25
+ { SettingRoutes ( Stack ) }
26
+ </ Stack . Navigator >
27
+ </ OutIsFocused . Provider >
22
28
)
23
29
}
24
30
25
31
function Settings ( ) {
26
32
const insets = useSafeAreaInsets ( )
33
+ const isFocused = useContext ( OutIsFocused )
27
34
const { opacity } = useContext ( TabBarBackgroundContext )
28
35
const tabBarHeight = useBottomTabBarHeight ( )
29
- useEffect ( ( ) => {
30
- opacity . value = 1
31
- return ( ) => {
32
- opacity . value = 1
33
- }
34
- } , [ opacity ] )
35
-
36
- const animatedScrollY = useAnimatedValue ( 0 )
37
- const handleScroll = useEventCallback (
38
- ( { nativeEvent } : NativeSyntheticEvent < NativeScrollEvent > ) => {
39
- const { contentOffset, contentSize, layoutMeasurement } = nativeEvent
40
-
41
- const distanceFromBottom = contentSize . height - layoutMeasurement . height - contentOffset . y
42
36
37
+ const calculateOpacity = useCallback (
38
+ ( contentHeight : number , viewportHeight : number , scrollY : number ) => {
39
+ const distanceFromBottom = contentHeight - viewportHeight - scrollY
43
40
const fadeThreshold = 50
44
41
45
42
if ( distanceFromBottom <= fadeThreshold ) {
@@ -48,13 +45,38 @@ function Settings() {
48
45
} else {
49
46
opacity . value = withTiming ( 1 , { duration : 150 } )
50
47
}
51
- animatedScrollY . setValue ( nativeEvent . contentOffset . y )
52
48
} ,
49
+ [ opacity ] ,
53
50
)
51
+
52
+ useEffect ( ( ) => {
53
+ if ( ! isFocused ) return
54
+ const scrollView = scrollRef . current
55
+ if ( scrollView ) {
56
+ const node = findNodeHandle ( scrollView )
57
+ if ( node ) {
58
+ UIManager . measure ( node , ( x , y , width , height ) => {
59
+ calculateOpacity ( height , height , 0 )
60
+ } )
61
+ }
62
+ }
63
+ } , [ opacity , isFocused , calculateOpacity ] )
64
+
65
+ const animatedScrollY = useAnimatedValue ( 0 )
66
+ const handleScroll = useEventCallback (
67
+ ( { nativeEvent } : NativeSyntheticEvent < NativeScrollEvent > ) => {
68
+ const { contentOffset, contentSize, layoutMeasurement } = nativeEvent
69
+ calculateOpacity ( contentSize . height , layoutMeasurement . height , contentOffset . y )
70
+ animatedScrollY . setValue ( contentOffset . y )
71
+ } ,
72
+ )
73
+
74
+ const scrollRef = useRef < ScrollView > ( null )
54
75
return (
55
76
< ScrollView
56
77
scrollEventThrottle = { 16 }
57
78
onScroll = { handleScroll }
79
+ ref = { scrollRef }
58
80
style = { { paddingTop : insets . top } }
59
81
className = "bg-system-background flex-1"
60
82
contentContainerStyle = { { paddingBottom : insets . bottom + tabBarHeight } }
0 commit comments