diff --git a/example/ScrollBottomSheet.tsx b/example/ScrollBottomSheet.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/index.tsx b/src/index.tsx index 907bb32..675f067 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -18,6 +18,7 @@ import Animated, { Clock, clockRunning, cond, + debug, Easing, eq, event, @@ -152,13 +153,14 @@ export class ScrollBottomSheet extends Component> { // @ts-ignore this.scrollComponent = Animated.createAnimatedComponent(ScrollComponent); const snapPoints = this.getNormalisedSnapPoints(); + console.log(snapPoints); const openPosition = snapPoints[0]; const closedPosition = snapPoints[snapPoints.length - 1]; const initialSnap = snapPoints[props.initialSnapIndex]; + const tempDestSnapPoint = new Value(0); const animationClock = new Clock(); const dragY = new Value(0); - const isAndroid = new Value(Platform.OS === 'android' ? 1 : 0); const prevTranslateYOffset = new Value(initialSnap); const handleOldGestureState = new Value(-1); const drawerOldGestureState = new Value(-1); @@ -173,14 +175,6 @@ export class ScrollBottomSheet extends Component> { const scrollUpAndPullDown = new Value(0); const snapToDifferentThanTopWithHandle = new Value(0); - call([lastSnap], ([value]) => { - // This is the TapGHandler trick on iOS - // @ts-ignore - this.iOSMasterDrawer?.current?.setNativeProps({ - maxDeltaY: value - this.getNormalisedSnapPoints()[0], - }); - }); - this.onHandleGestureEvent = event([ { nativeEvent: { @@ -209,10 +203,11 @@ export class ScrollBottomSheet extends Component> { const didHandleGestureBegin = eq(handleOldGestureState, GestureState.BEGAN); - const lastEndScrollY = [ - cond(didHandleGestureBegin, set(dragWithHandle, 1)), - cond(and(eq(dragWithHandle, 1), eq(isAndroid, 1)), lastStartScrollY, 0), - ]; + const scrollY = cond( + didHandleGestureBegin, + [set(dragWithHandle, 1), 0], + cond(eq(dragWithHandle, 1), 0, lastStartScrollY) + ); const didGestureFinish = or( eq(handleOldGestureState, GestureState.ACTIVE), @@ -245,40 +240,21 @@ export class ScrollBottomSheet extends Component> { ); const currentSnapPoint = (i = 0): Animated.Node | number => - cond( - eq(add(i, 1), snapPoints.length), - add(snapPoints[i], extraOffset), - cond( - greaterThan( - abs(sub(add(snapPoints[0], extraOffset), endOffsetY)), - abs(sub(add(snapPoints[i], extraOffset), endOffsetY)) - ), - add(snapPoints[i], extraOffset), - currentSnapPoint(i + 1) - ) - ); - - const translateYOffset = cond(didGestureFinish, [ - didScrollUpAndPullDown, - setTranslationY, - set(destSnapPoint, currentSnapPoint()), - set(dragY, 0), - set( - lastSnap, - sub( - destSnapPoint, - cond(eq(didScrollUpAndPullDown, 1), lastStartScrollY, 0) - ) - ), - runTiming({ - clock: animationClock, - from: add(prevTranslateYOffset, translationY), - duration: 250, - to: destSnapPoint, - }), - ]); - - function runTiming({ clock, from, to, duration = 400 }: TimingParams) { + i === snapPoints.length + ? tempDestSnapPoint + : cond( + greaterThan( + abs(sub(tempDestSnapPoint, endOffsetY)), + abs(sub(add(snapPoints[i], extraOffset), endOffsetY)) + ), + [ + set(tempDestSnapPoint, add(snapPoints[i], extraOffset)), + currentSnapPoint(i + 1), + ], + currentSnapPoint(i + 1) + ); + + const runTiming = ({ clock, from, to, duration = 400 }: TimingParams) => { const state = { finished: new Value<0 | 1>(0), position: new Value(0), @@ -292,20 +268,6 @@ export class ScrollBottomSheet extends Component> { easing: Easing.inOut(Easing.ease), }; - call([state.finished, lastSnap], ([finished, lastSnapValue]) => { - if (finished === 1) { - const decelerationRate = Platform.select({ - ios: 0.998, - android: lastSnapValue === snapPoints[0] ? 0.985 : 0, - }); - // @ts-ignore - this.contentComponentRef.current?._component?.setNativeProps({ - decelerationRate, - disableIntervalMomentum: false, - }); - } - }); - return [ cond(clockRunning(clock), 0, [ // If the clock isn't running we reset all the animation params and start the clock @@ -319,6 +281,19 @@ export class ScrollBottomSheet extends Component> { // we run the step here that is going to update position timing(clock, state, config), // If the animation is over we stop the clock + call([state.finished, lastSnap], ([finished, lastSnapValue]) => { + if (finished === 1) { + const decelerationRate = Platform.select({ + ios: 0.998, + android: lastSnapValue === snapPoints[0] ? 0.985 : 0, + }); + // @ts-ignore + this.contentComponentRef.current?._component?.setNativeProps({ + decelerationRate, + disableIntervalMomentum: false, + }); + } + }), cond( state.finished, [ @@ -342,8 +317,7 @@ export class ScrollBottomSheet extends Component> { eq(destSnapPoint, snapPoints[0]) ), [ - // @ts-ignore - cond(eq(isAndroid, 1), set(lastEndScrollY, 0)), + // cond(eq(isAndroid, 1), set(lastEndScrollY, 0)), set(snapToDifferentThanTopWithHandle, 0), set(dragWithHandle, 0), ] @@ -355,22 +329,42 @@ export class ScrollBottomSheet extends Component> { state.position ), ]; - } + }; + + const translateYOffset = cond( + didGestureFinish, + [ + didScrollUpAndPullDown, + setTranslationY, + set(tempDestSnapPoint, add(snapPoints[0], extraOffset)), + set(destSnapPoint, currentSnapPoint()), + set(dragY, 0), + set( + lastSnap, + sub( + destSnapPoint, + cond(eq(didScrollUpAndPullDown, 1), lastStartScrollY, 0) + ) + ), + call([lastSnap], ([value]) => { + // This is the TapGHandler trick on iOS + // @ts-ignore + this.iOSMasterDrawer?.current?.setNativeProps({ + maxDeltaY: value - this.getNormalisedSnapPoints()[0], + }); + }), + runTiming({ + clock: animationClock, + from: add(prevTranslateYOffset, translationY), + duration: 250, + to: destSnapPoint, + }), + ], + prevTranslateYOffset + ); this.translateY = interpolate( - add( - translateYOffset, - lastEndScrollY, - dragY, - multiply( - cond( - and(eq(isAndroid, 0), eq(dragWithHandle, 1)), - 0, - lastStartScrollY - ), - -1 - ) - ), + add(translateYOffset, dragY, multiply(scrollY, -1)), { inputRange: [openPosition, closedPosition], outputRange: [openPosition, closedPosition],