make scrollview automatically adapt to footer height

This commit is contained in:
Samuel Newman
2025-06-19 22:46:12 +03:00
parent 95f9cc1ed5
commit df975ddcfa
10 changed files with 199 additions and 161 deletions
+27 -30
View File
@@ -1,19 +1,24 @@
import {forwardRef, memo, useContext, useMemo} from 'react'
import {StyleSheet, View, type ViewProps, type ViewStyle} from 'react-native'
import {type StyleProp} from 'react-native'
import {
ScrollView,
type ScrollViewProps,
type StyleProp,
StyleSheet,
View,
type ViewProps,
type ViewStyle,
} from 'react-native'
import {
KeyboardAwareScrollView,
type KeyboardAwareScrollViewProps,
} from 'react-native-keyboard-controller'
import Animated, {
type AnimatedScrollViewProps,
useAnimatedProps,
} from 'react-native-reanimated'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {useShellLayout} from '#/state/shell/shell-layout'
import {
android,
atoms as a,
ios,
useBreakpoints,
useLayoutBreakpoints,
useTheme,
@@ -22,7 +27,7 @@ import {
import {useDialogContext} from '#/components/Dialog'
import {CENTER_COLUMN_OFFSET, SCROLLBAR_OFFSET} from '#/components/Layout/const'
import {ScrollbarOffsetContext} from '#/components/Layout/context'
import {IS_WEB} from '#/env'
import {IS_IOS, IS_WEB} from '#/env'
export * from '#/components/Layout/const'
export * as Header from '#/components/Layout/Header'
@@ -52,9 +57,7 @@ export const Screen = memo(function Screen({
)
})
export type ContentProps = AnimatedScrollViewProps & {
style?: StyleProp<ViewStyle>
contentContainerStyle?: StyleProp<ViewStyle>
export type ContentProps = ScrollViewProps & {
ignoreTabletLayoutOffset?: boolean
}
@@ -62,7 +65,7 @@ export type ContentProps = AnimatedScrollViewProps & {
* Default scroll view for simple pages
*/
export const Content = memo(
forwardRef<Animated.ScrollView, ContentProps>(function Content(
forwardRef<ScrollView, ContentProps>(function Content(
{
children,
style,
@@ -74,39 +77,33 @@ export const Content = memo(
) {
const t = useTheme()
const {footerHeight} = useShellLayout()
const animatedProps = useAnimatedProps(() => {
return {
scrollIndicatorInsets: {
bottom: footerHeight.get(),
top: 0,
right: 1,
},
} satisfies AnimatedScrollViewProps
})
return (
<Animated.ScrollView
<ScrollView
ref={ref}
id="content"
automaticallyAdjustsScrollIndicatorInsets={false}
scrollIndicatorInsets={{
bottom: footerHeight,
top: 0,
right: 1,
}}
indicatorStyle={t.scheme === 'dark' ? 'white' : 'black'}
// sets the scroll inset to the height of the footer
animatedProps={animatedProps}
style={[scrollViewStyles.common, style]}
contentInset={ios({top: 0, left: 0, bottom: footerHeight, right: 0})}
contentContainerStyle={[
scrollViewStyles.contentContainer,
!IS_IOS && {paddingBottom: footerHeight},
contentContainerStyle,
]}
{...props}>
{IS_WEB ? (
<Center ignoreTabletLayoutOffset={ignoreTabletLayoutOffset}>
{/* @ts-expect-error web only -esb */}
{children}
</Center>
) : (
children
)}
</Animated.ScrollView>
</ScrollView>
)
}),
)
@@ -115,9 +112,6 @@ const scrollViewStyles = StyleSheet.create({
common: {
width: '100%',
},
contentContainer: {
paddingBottom: 100,
},
})
export type KeyboardAwareContentProps = KeyboardAwareScrollViewProps & {
@@ -136,11 +130,14 @@ export const KeyboardAwareContent = memo(function LayoutKeyboardAwareContent({
contentContainerStyle,
...props
}: KeyboardAwareContentProps) {
const {footerHeight} = useShellLayout()
return (
<KeyboardAwareScrollView
style={[scrollViewStyles.common, style]}
contentInset={ios({top: 0, left: 0, bottom: footerHeight, right: 0})}
contentContainerStyle={[
scrollViewStyles.contentContainer,
android({paddingBottom: footerHeight}),
web({paddingBottom: footerHeight}),
contentContainerStyle,
]}
keyboardShouldPersistTaps="handled"