Skip to content

Commit 437a790

Browse files
committed
fix(rn-base): fix SafeNavigationScrollView and impl blur effect header
Signed-off-by: Innei <tukon479@gmail.com>
1 parent 364d23f commit 437a790

File tree

6 files changed

+92
-20
lines changed

6 files changed

+92
-20
lines changed

apps/mobile/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@follow/mobile",
3-
"version": "1.0.0",
3+
"version": "0.1.0",
44
"private": true,
55
"main": "src/main.tsx",
66
"scripts": {

apps/mobile/src/components/common/SafeNavigationScrollView.tsx

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,68 @@
11
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs"
22
import { useHeaderHeight } from "@react-navigation/elements"
33
import { router, Stack, useNavigation } from "expo-router"
4-
import type { FC } from "react"
4+
import type { FC, PropsWithChildren } from "react"
5+
import { createContext, useContext, useEffect, useMemo, useState } from "react"
56
import type { ScrollViewProps } from "react-native"
6-
import { ScrollView, TouchableOpacity, View } from "react-native"
7+
import {
8+
Animated as RNAnimated,
9+
StyleSheet,
10+
TouchableOpacity,
11+
useAnimatedValue,
12+
View,
13+
} from "react-native"
14+
import type { ReanimatedScrollEvent } from "react-native-reanimated/lib/typescript/hook/commonTypes"
715
import { useSafeAreaInsets } from "react-native-safe-area-context"
816
import { useColor } from "react-native-uikit-colors"
917

1018
import { MingcuteLeftLineIcon } from "@/src/icons/mingcute_left_line"
1119

12-
import { BlurEffectWithBottomBorder } from "./BlurEffect"
20+
import { AnimatedScrollView } from "./AnimatedComponents"
21+
import { ThemedBlurView } from "./ThemedBlurView"
1322

14-
type SafeNavigationScrollViewProps = ScrollViewProps & {
23+
type SafeNavigationScrollViewProps = Omit<ScrollViewProps, "onScroll"> & {
1524
withHeaderBlur?: boolean
16-
}
25+
onScroll?: (e: ReanimatedScrollEvent) => void
26+
27+
// For scroll view content adjustment behavior
28+
withTopInset?: boolean
29+
withBottomInset?: boolean
30+
} & PropsWithChildren
31+
const NavigationContext = createContext<{
32+
scrollY: RNAnimated.Value
33+
} | null>(null)
1734

1835
export const SafeNavigationScrollView: FC<SafeNavigationScrollViewProps> = ({
1936
children,
2037

2138
withHeaderBlur = true,
39+
onScroll,
40+
41+
withBottomInset = false,
42+
withTopInset = false,
43+
2244
...props
2345
}) => {
2446
const insets = useSafeAreaInsets()
2547
const tabBarHeight = useBottomTabBarHeight()
2648
const headerHeight = useHeaderHeight()
2749

50+
const scrollY = useAnimatedValue(0)
51+
2852
return (
29-
<>
53+
<NavigationContext.Provider value={useMemo(() => ({ scrollY }), [scrollY])}>
3054
{withHeaderBlur && <NavigationBlurEffectHeader />}
31-
<ScrollView contentInsetAdjustmentBehavior="automatic" {...props}>
32-
<View style={{ height: headerHeight - insets.top }} />
55+
<AnimatedScrollView
56+
onScroll={RNAnimated.event([{ nativeEvent: { contentOffset: { y: scrollY } } }], {
57+
useNativeDriver: true,
58+
})}
59+
{...props}
60+
>
61+
<View style={{ height: headerHeight - (withTopInset ? insets.top : 0) }} />
3362
<View>{children}</View>
34-
<View style={{ height: tabBarHeight - insets.bottom }} />
35-
</ScrollView>
36-
</>
63+
<View style={{ height: tabBarHeight - (withBottomInset ? insets.bottom : 0) }} />
64+
</AnimatedScrollView>
65+
</NavigationContext.Provider>
3766
)
3867
}
3968

@@ -45,10 +74,35 @@ export const NavigationBlurEffectHeader = (props: NavigationBlurEffectHeaderProp
4574

4675
const canBack = useNavigation().canGoBack()
4776

77+
const { scrollY } = useContext(NavigationContext)!
78+
79+
const border = useColor("opaqueSeparator")
80+
81+
const [opacity, setOpacity] = useState(0)
82+
83+
useEffect(() => {
84+
const id = scrollY.addListener(({ value }) => {
85+
setOpacity(Math.min(1, Math.max(0, Math.min(1, value / 10))))
86+
})
87+
88+
return () => {
89+
scrollY.removeListener(id)
90+
}
91+
}, [scrollY])
92+
4893
return (
4994
<Stack.Screen
5095
options={{
51-
headerBackground: BlurEffectWithBottomBorder,
96+
headerBackground: () => (
97+
<ThemedBlurView
98+
style={{
99+
...StyleSheet.absoluteFillObject,
100+
opacity,
101+
borderBottomWidth: StyleSheet.hairlineWidth,
102+
borderBottomColor: border,
103+
}}
104+
/>
105+
),
52106
headerTransparent: true,
53107

54108
headerLeft: canBack

apps/mobile/src/components/ui/grouped/GroupedList.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,19 @@ import { Pressable, StyleSheet, Text, View } from "react-native"
88
import { RightCuteReIcon } from "@/src/icons/right_cute_re"
99
import { useColor } from "@/src/theme/colors"
1010

11-
export const GroupedInsetListCard: FC<PropsWithChildren> = ({ children }) => {
11+
export const GroupedInsetListCard: FC<PropsWithChildren & ViewProps> = ({
12+
children,
13+
className,
14+
...props
15+
}) => {
1216
return (
13-
<View className="bg-secondary-system-grouped-background mx-4 flex-1 overflow-hidden rounded-[10px]">
17+
<View
18+
{...props}
19+
className={cn(
20+
"bg-secondary-system-grouped-background mx-4 flex-1 overflow-hidden rounded-[10px]",
21+
className,
22+
)}
23+
>
1424
{React.Children.map(children, (child, index) => {
1525
const isLast = index === React.Children.count(children) - 1
1626
return (
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
import { Text, View } from "react-native"
22

3+
import {
4+
NavigationBlurEffectHeader,
5+
SafeNavigationScrollView,
6+
} from "@/src/components/common/SafeNavigationScrollView"
7+
38
export const AboutScreen = () => {
49
return (
5-
<View className="flex-1 items-center justify-center">
6-
<Text>About</Text>
7-
</View>
10+
<SafeNavigationScrollView className="bg-system-grouped-background">
11+
<NavigationBlurEffectHeader title="About" />
12+
<View className="flex-1 items-center justify-center">
13+
<Text>About</Text>
14+
</View>
15+
</SafeNavigationScrollView>
816
)
917
}

apps/mobile/src/modules/settings/routes/Privacy.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const PrivacyScreen = () => {
1313
return (
1414
<SafeNavigationScrollView className="bg-system-grouped-background">
1515
<NavigationBlurEffectHeader title="Privacy" />
16-
<GroupedInsetListCard>
16+
<GroupedInsetListCard className="mt-4">
1717
<GroupedInsetListNavigationLink
1818
label="Teams"
1919
onPress={() => {

apps/mobile/src/screens/(stack)/(tabs)/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export default function Index() {
3737
}}
3838
/>
3939

40-
<SafeNavigationScrollView>
40+
<SafeNavigationScrollView contentInsetAdjustmentBehavior="automatic" withTopInset>
4141
<View className="flex min-h-96 items-center justify-center bg-zinc-300">
4242
<Text className="text-center text-2xl text-accent">EntryList Placeholder</Text>
4343
</View>

0 commit comments

Comments
 (0)