diff --git a/example/App.tsx b/example/App.tsx index f39ab63..7024869 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -1,5 +1,12 @@ import React from 'react'; -import { StyleSheet, Text, View, Dimensions, Button } from 'react-native'; +import { + StyleSheet, + Text, + View, + Dimensions, + Button, + StatusBar, +} from 'react-native'; import Animated, { Value, interpolate, @@ -30,10 +37,11 @@ export default function App() { return ( + @@ -47,10 +55,8 @@ export default function App() { console.log('Next snap index: ', index); }} renderHandle={() => ( - - - - + + )} contentContainerStyle={styles.contentContainerStyle} @@ -101,20 +107,10 @@ const styles = StyleSheet.create({ padding: 24, backgroundColor: '#F3F4F9', }, - headerContainer: { - overflow: 'hidden', - paddingTop: 20, - }, header: { alignItems: 'center', - backgroundColor: '#F3F4F9', - borderTopWidth: 0.5, - borderLeftWidth: 0.5, - borderRightWidth: 0.5, + backgroundColor: 'white', paddingTop: 20, - borderLeftColor: '#F3F4F9', - borderRightColor: '#F3F4F9', - borderTopColor: '#F3F4F9', borderTopLeftRadius: 20, borderTopRightRadius: 20, shadowColor: '#000', @@ -129,6 +125,7 @@ const styles = StyleSheet.create({ panelHandle: { width: 40, height: 2, + backgroundColor: 'rgba(0,0,0,0.3)', borderRadius: 4, marginBottom: 10, }, diff --git a/src/index.tsx b/src/index.tsx index 3febd53..862a2e1 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -8,6 +8,7 @@ import { SectionList, SectionListProps, StyleSheet, + ScrollView, View, } from 'react-native'; import Animated, { @@ -40,7 +41,6 @@ import { NativeViewGestureHandler, PanGestureHandler, PanGestureHandlerProperties, - ScrollView, State as GestureState, TapGestureHandler, } from 'react-native-gesture-handler'; @@ -111,10 +111,13 @@ interface TimingParams { type CommonProps = { /** * Array of numbers that indicate the different resting positions of the bottom sheet (in dp or %), starting from the top. + * If a percentage is used, that would translate to the relative amount of the total window height. + * For instance, if 50% is used, that'd be windowHeight * 0.5. If you wanna take into account safe areas during + * the calculation, such as status bars and notches, please use 'topInset' prop */ snapPoints: Array; /** - * Index that references the initial settled position of the drawer + * Index that references the initial resting position of the drawer, starting from the top */ initialSnapIndex: number; /** @@ -159,17 +162,22 @@ export class ScrollBottomSheet extends Component> { /** * Gesture Handler references */ + private masterDrawer = React.createRef(); private drawerHandleRef = React.createRef(); private drawerContentRef = React.createRef(); private scrollComponentRef = React.createRef(); - private masterDrawer = React.createRef(); - /** * Reference to FlatList, ScrollView or SectionList in order to execute its imperative methods. */ private contentComponentRef = React.createRef(); + /** + * ScrollView prop + */ private onScrollBeginDrag: ScrollViewProps['onScrollBeginDrag']; + /** + * Pan gesture handler events for drawer handle and content + */ private onHandleGestureEvent: PanGestureHandlerProperties['onGestureEvent']; private onDrawerGestureEvent: PanGestureHandlerProperties['onGestureEvent']; /** @@ -180,9 +188,22 @@ export class ScrollBottomSheet extends Component> { * Animated value that keeps track of the position: 0 => closed, 1 => opened */ private position: Animated.Node; + /** + * Flag to indicate imperative snapping + */ private isManuallySetValue: Animated.Value = new Value(0); + /** + * Manual snapping amount + */ private manualYOffset: Animated.Value = new Value(0); + /** + * Keeps track of the current index + */ private nextSnapIndex: Animated.Value; + /** + * Deceleration rate of the scroll component. This is used only on Android to + * compensate the unexpected glide it gets sometimes. + */ private decelerationRate: Animated.Value; private prevSnapIndex = -1; @@ -199,36 +220,40 @@ export class ScrollBottomSheet extends Component> { initialSnapIndex, animationConfig = { duration: 250, easing: Easing.inOut(Easing.ease) }, } = props; + const ScrollComponent = this.getScrollComponent(); // @ts-ignore this.scrollComponent = Animated.createAnimatedComponent(ScrollComponent); + const snapPoints = this.getNormalisedSnapPoints(); const openPosition = snapPoints[0]; const closedPosition = snapPoints[snapPoints.length - 1]; const initialSnap = snapPoints[initialSnapIndex]; const tempDestSnapPoint = new Value(0); this.nextSnapIndex = new Value(initialSnapIndex); + const isAndroid = new Value(Number(Platform.OS === 'android')); const initialDecelerationRate = Platform.select({ android: props.initialSnapIndex === 0 ? ANDROID_NORMAL_DECELERATION_RATE : 0, ios: IOS_NORMAL_DECELERATION_RATE, }); - this.decelerationRate = new Value(initialDecelerationRate); const animationClock = new Clock(); const animationPosition = new Value(0); const animationFinished = new Value(0); const animationFrameTime = new Value(0); - const dragY = new Value(0); - const prevTranslateYOffset = new Value(initialSnap); + const handleGestureState = new Value(-1); const handleOldGestureState = new Value(-1); const drawerGestureState = new Value(-1); const drawerOldGestureState = new Value(-1); + + const dragY = new Value(0); const velocityY = new Value(0); const lastStartScrollY = new Value(0); + const prevTranslateYOffset = new Value(initialSnap); const translationY = new Value(initialSnap); const destSnapPoint = new Value(0); @@ -606,11 +631,11 @@ export class ScrollBottomSheet extends Component> { simultaneousHandlers={this.drawerContentRef} >