Skip to content

Commit

Permalink
refactor: updated handling animated heights (#451)
Browse files Browse the repository at this point in the history
* refactor: updated handling animated heights

* refactor: updated code base to handle container offsets

* chore: updated examples
  • Loading branch information
gorhom committed May 22, 2021
1 parent db1994d commit b9313ba
Show file tree
Hide file tree
Showing 30 changed files with 465 additions and 307 deletions.
1 change: 1 addition & 0 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@gorhom/showcase-template": "^2.0.4",
"@react-native-community/blur": "^3.6.0",
"@react-native-community/masked-view": "0.1.11",
"@react-navigation/bottom-tabs": "^5.11.11",
"@react-navigation/material-top-tabs": "^5.3.15",
"@react-navigation/native": "^5.9.4",
"@react-navigation/stack": "^5.14.4",
Expand Down
294 changes: 120 additions & 174 deletions example/src/Dev.tsx
Original file line number Diff line number Diff line change
@@ -1,218 +1,164 @@
/* eslint-disable no-console */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useCallback, useMemo, useRef, useState } from 'react';
import { View, StyleSheet, Dimensions, StatusBar } from 'react-native';
import { createStackNavigator } from '@react-navigation/stack';
import { useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
import { StyleSheet, View } from 'react-native';
import { DarkTheme, NavigationContainer } from '@react-navigation/native';
import {
SafeAreaProvider,
useSafeAreaInsets,
} from 'react-native-safe-area-context';
import BottomSheet from '@gorhom/bottom-sheet';
createBottomTabNavigator,
useBottomTabBarHeight,
} from '@react-navigation/bottom-tabs';
import {
BottomSheetFlatList,
BottomSheetModal,
BottomSheetModalProvider,
} from '@gorhom/bottom-sheet';
import Animated, {
useAnimatedStyle,
useSharedValue,
} from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { createContactListMockData } from './utilities';
import ContactItem from './components/contactItem';
import SearchHandle from './components/searchHandle';
import Button from './components/button';
import ContactList from './components/contactList';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { Button } from 'react-native';

const SNAP_POINTS = [150, 300];
const DATA = createContactListMockData(30);

const { height: windowHeight } = Dimensions.get('window');
const keyExtractor = (item: any, index: number) => `${item.name}.${index}`;

const BasicExample = () => {
const App = () => {
//#region state
const shownHeader = useRef(true);
const [dynamicSnapPoint, setDynamicSnapPoint] = useState(300);
const bottomSheetRef = useRef<BottomSheetModal>(null);
const [filter, setFilter] = useState('');
//#endregion

//#region hooks
const { setOptions } = useNavigation();
const bottomSheetRef = useRef<BottomSheet>(null);
const { top: topSafeArea, bottom: bottomSafeArea } = useSafeAreaInsets();
const { top: topSafeArea } = useSafeAreaInsets();
const bottomSafeArea = useBottomTabBarHeight();
//#endregion

//#region variables
const snapPoints = useMemo(() => [150, 400, '100%'], []);
const animatedPosition = useSharedValue<number>(0);
const animatedContainerHeight = useSharedValue<number>(800);
//#region animated values
const data = useMemo(
() =>
filter === '' ? DATA : DATA.filter(item => item.name.includes(filter)),
[filter]
);
const animatedPosition = useSharedValue(0);
//#endregion

//#region styles
const containerStyle = useMemo(
() => ({
...styles.container,
paddingTop: topSafeArea,
}),
[topSafeArea]
);

const firstSnapPointLineStyle = useMemo(
() => [
styles.line,
{
height: snapPoints[0],
},
],
[snapPoints]
);

const secondSnapPointLineStyle = useMemo(
() => [
styles.line,
{
height: snapPoints[1],
},
],
[snapPoints]
);

const safeBottomLineStyle = useMemo(
() => [
styles.line,
{
height: bottomSafeArea,
},
],
[bottomSafeArea]
);

const sheetLineAnimatedStyle = useAnimatedStyle(() => ({
transform: [{ translateY: animatedPosition.value }],
const positionLineAnimatedStyle = useAnimatedStyle(() => ({
top: animatedPosition.value,
}));
const sheetLineStyle = useMemo(
() => [styles.sheetLine, sheetLineAnimatedStyle],
[sheetLineAnimatedStyle]
);
//#endregion

//#region callbacks
const handleSheetChanges = useCallback((index: number) => {
console.log('handleSheetChanges', index);
}, []);
const handleSnapPress = useCallback(index => {
bottomSheetRef.current?.snapToIndex(index);
}, []);
const handleSnapPosition = useCallback(position => {
bottomSheetRef.current?.snapToIndex(position);
}, []);
const handleClosePress = useCallback(() => {
bottomSheetRef.current?.close();
}, []);
const handleIncreaseDynamicSnapPoint = useCallback(() => {
setDynamicSnapPoint(state => state + 50);
}, []);
const handleHideHeaderPress = useCallback(() => {
shownHeader.current = !shownHeader.current;
setOptions({
headerShown: shownHeader.current,
});
}, [setOptions]);
//#endregion

// renders
return (
<View style={containerStyle}>
{/* <Button
label="Increase Dynamic Snap Point"
style={styles.buttonContainer}
onPress={handleIncreaseDynamicSnapPoint}
/> */}
<Button
label="Snap To 0"
style={styles.buttonContainer}
onPress={() => handleSnapPress(0)}
//#region render
const renderItem = useCallback(
({ item, index }) => (
<ContactItem
key={`${item.name}.${index}`}
title={`${index}: ${item.name}`}
subTitle={item.jobTitle}
/>
<Button
label="Snap To 1"
style={styles.buttonContainer}
onPress={() => handleSnapPress(1)}
/>
<Button
label="Snap To 500px"
style={styles.buttonContainer}
onPress={() => handleSnapPosition(500)}
/>
<Button
label="Close"
style={styles.buttonContainer}
onPress={handleClosePress}
),
[]
);
const renderHandle = useCallback(
props => (
<SearchHandle
key="search-handle"
initialValue={filter}
onChange={setFilter}
{...props}
/>

),
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);
return (
<View style={styles.container}>
<Button
label="Hide Header"
style={styles.buttonContainer}
onPress={handleHideHeaderPress}
title="Present"
onPress={() => bottomSheetRef.current?.present()}
/>
<BottomSheet
<BottomSheetModal
ref={bottomSheetRef}
snapPoints={snapPoints}
animatedPosition={animatedPosition}
snapPoints={SNAP_POINTS}
keyboardBehavior="interactive"
// topInset={topSafeArea}
handleComponent={SearchHandle}
animateOnMount={true}
// onChange={handleSheetChanges}
topInset={topSafeArea}
bottomInset={bottomSafeArea}
animatedPosition={animatedPosition}
enablePanDownToClose={false}
handleComponent={renderHandle}
>
{/* <ContactList type="FlatList" count={20} /> */}
<View style={{}}>
<View
pointerEvents="none"
style={{
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
height: bottomSafeArea,
borderWidth: 1,
backgroundColor: 'red',
}}
/>
</View>
</BottomSheet>
{/* <Animated.View pointerEvents="none" style={sheetLineStyle} /> */}
<View pointerEvents="none" style={secondSnapPointLineStyle} />
<View pointerEvents="none" style={firstSnapPointLineStyle} />
<View pointerEvents="none" style={safeBottomLineStyle} />
<BottomSheetFlatList
data={data}
renderItem={renderItem}
keyExtractor={keyExtractor}
style={styles.flatlist}
contentContainerStyle={styles.flatlistContainer}
/>
</BottomSheetModal>

{SNAP_POINTS.map(snapPoint => (
<View
pointerEvents="none"
key={`line-${snapPoint}`}
style={[styles.line, { bottom: snapPoint }]}
/>
))}

<View
pointerEvents="none"
style={[styles.line, { top: topSafeArea, backgroundColor: 'green' }]}
/>
<View
pointerEvents="none"
style={[
styles.line,
{ bottom: bottomSafeArea, backgroundColor: 'green' },
]}
/>
<Animated.View
pointerEvents="none"
style={[
styles.line,
{ backgroundColor: 'blue' },
positionLineAnimatedStyle,
]}
/>
</View>
);
//#endregion
};

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#555',
padding: 24,
},
buttonContainer: {
marginBottom: 6,
},
textInput: {
backgroundColor: 'red',
opacity: 1,
padding: 6,
margin: 6,
borderRadius: 24,
justifyContent: 'center',
},
line: {
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
borderWidth: 1,
},
sheetLine: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
height: 1,
backgroundColor: 'red',
},
flatlist: {
flex: 1,
},
flatlistContainer: {
paddingHorizontal: 24,
},
});

const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();

export default () => (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="app" component={BasicExample} />
</Stack.Navigator>
</NavigationContainer>
<BottomSheetModalProvider>
<NavigationContainer theme={DarkTheme}>
<Tab.Navigator>
<Tab.Screen name="App" component={App} />
</Tab.Navigator>
</NavigationContainer>
</BottomSheetModalProvider>
);
Loading

0 comments on commit b9313ba

Please sign in to comment.