@@ -78,9 +78,14 @@ export enum DirectionType {
7878 top = 'top' ,
7979}
8080
81+ interface Point {
82+ moveX : number ;
83+ moveY : number ;
84+ }
85+
8186interface IState {
82- sideMenuOpenValue : any ;
83- sideMenuOverlayOpacity : any ;
87+ sideMenuOpenValue : Animated . Value ;
88+ sideMenuOverlayOpacity : Animated . Value ;
8489 sideMenuSwipingStarted : boolean ;
8590 sideMenuIsDismissing : boolean ;
8691 screenHeight : number ;
@@ -97,6 +102,7 @@ interface IProps {
97102 fadeOpacity : number ;
98103 drawerScreenWidth : number | string ;
99104 drawerScreenHeight : number | string ;
105+ animateDrawerExpanding ?: boolean ;
100106 style : any ;
101107}
102108
@@ -124,7 +130,7 @@ interface DrawerReverseDirectionInterface {
124130}
125131
126132interface SwipeMoveInterface {
127- value : number ;
133+ value : Point ;
128134 direction : string ;
129135}
130136
@@ -142,13 +148,16 @@ class RNNDrawer {
142148 private readonly drawerWidth : number ;
143149 private readonly drawerHeight : number ;
144150 private readonly drawerOpenedValues : DrawerDirectionValuesInterface ;
151+ private readonly initialValues : DrawerDirectionValuesInterface ;
145152 private panResponder : PanResponderInstance ;
146- private animatedDrawer : any ;
147- private animatedOpacity : any ;
148- private unsubscribeSwipeStart : any ;
149- private unsubscribeSwipeMove : any ;
150- private unsubscribeSwipeEnd : any ;
151- private unsubscribeDismissDrawer : any ;
153+ private animatedDrawer ! : Animated . CompositeAnimation ;
154+ private animatedOpacity ! : Animated . CompositeAnimation ;
155+ private unsubscribeSwipeStart ! : ( ) => void ;
156+ private unsubscribeSwipeMove ! : ( ) => void ;
157+ private unsubscribeSwipeEnd ! : ( ) => void ;
158+ private unsubscribeDismissDrawer ! : ( ) => void ;
159+ private panningStartedPoint : Point = { moveX : 0 , moveY : 0 } ;
160+ private startedFromSideMenu : boolean = false ;
152161
153162 static defaultProps = {
154163 animationOpenTime : 300 ,
@@ -158,6 +167,7 @@ class RNNDrawer {
158167 fadeOpacity : 0.6 ,
159168 drawerScreenWidth : '80%' ,
160169 drawerScreenHeight : '100%' ,
170+ animateDrawerExpanding : true
161171 } ;
162172
163173 /**
@@ -186,9 +196,12 @@ class RNNDrawer {
186196 _evt : GestureResponderEvent ,
187197 _gestureState : PanResponderGestureState ,
188198 ) => {
189- const { dx } = _gestureState ;
199+ const { dx, dy } = _gestureState ;
190200
191- return Math . abs ( dx ) > 5 ;
201+ if ( this . props . direction === DirectionType . left || this . props . direction === DirectionType . right )
202+ return Math . abs ( dx ) > 5 ;
203+ else
204+ return Math . abs ( dy ) > 5 ;
192205 } ,
193206 onMoveShouldSetPanResponderCapture : (
194207 _evt : GestureResponderEvent ,
@@ -198,7 +211,9 @@ class RNNDrawer {
198211 _evt : GestureResponderEvent ,
199212 _gestureState : PanResponderGestureState ,
200213 ) => {
201- dispatch ( 'SWIPE_START' ) ;
214+ const { moveX, moveY } = _gestureState ;
215+
216+ dispatch ( 'SWIPE_START' , { moveX, moveY} ) ;
202217 } ,
203218 onPanResponderRelease : (
204219 _evt : GestureResponderEvent ,
@@ -221,10 +236,10 @@ class RNNDrawer {
221236 _evt : GestureResponderEvent ,
222237 _gestureState : PanResponderGestureState ,
223238 ) => {
224- const { moveX } = _gestureState ;
239+ const { moveX, moveY } = _gestureState ;
225240 const direction = this . props . direction || 'left' ;
226241
227- dispatch ( 'SWIPE_MOVE' , { value : moveX , direction } ) ;
242+ dispatch ( 'SWIPE_MOVE' , { value : { moveX, moveY } , direction } ) ;
228243 } ,
229244 } ) ;
230245
@@ -263,20 +278,20 @@ class RNNDrawer {
263278 this . drawerOpenedValues = {
264279 left : 0 ,
265280 right : this . screenWidth - this . drawerWidth ,
266- top : 0 ,
281+ top : this . drawerHeight - this . screenHeight ,
267282 bottom : this . screenHeight - this . drawerHeight ,
268283 } ;
269284
270- const initialValues : DrawerDirectionValuesInterface = {
285+ this . initialValues = {
271286 left : - this . drawerWidth ,
272287 right : this . screenWidth ,
273- top : - this . drawerHeight ,
288+ top : - this . screenHeight ,
274289 bottom : this . screenHeight ,
275290 } ;
276291
277292 /** Component State */
278293 this . state = {
279- sideMenuOpenValue : new Animated . Value ( initialValues [ props . direction ] ) ,
294+ sideMenuOpenValue : new Animated . Value ( this . initialValues [ props . direction ] ) ,
280295 sideMenuOverlayOpacity : new Animated . Value ( 0 ) ,
281296 sideMenuSwipingStarted : false ,
282297 sideMenuIsDismissing : false ,
@@ -310,13 +325,16 @@ class RNNDrawer {
310325 */
311326 componentDidMount ( ) {
312327 /** Props */
313- const { direction, fadeOpacity } = this . props ;
328+ const { direction, fadeOpacity, animateDrawerExpanding } = this . props ;
329+
330+ if ( typeof animateDrawerExpanding !== 'undefined' && ! animateDrawerExpanding )
331+ this . startedFromSideMenu = true ;
314332
315333 // Animate side menu open
316334 this . animatedDrawer = Animated . timing ( this . state . sideMenuOpenValue , {
317335 toValue : this . drawerOpenedValues [ direction ] ,
318336 duration : this . props . animationOpenTime ,
319- useNativeDriver : false ,
337+ useNativeDriver : true ,
320338 } ) ;
321339
322340 // Animate outside side menu opacity
@@ -325,7 +343,7 @@ class RNNDrawer {
325343 {
326344 toValue : fadeOpacity ,
327345 duration : this . props . animationOpenTime ,
328- useNativeDriver : false ,
346+ useNativeDriver : true ,
329347 } ,
330348 ) ;
331349 }
@@ -339,7 +357,7 @@ class RNNDrawer {
339357 this . registerListeners ( ) ;
340358
341359 // If there has been no Swiping, and this component appears, then just start the open animations
342- if ( ! this . state . sideMenuSwipingStarted ) {
360+ if ( ! this . state . sideMenuSwipingStarted && this . props . animateDrawerExpanding ) {
343361 this . animatedDrawer . start ( ) ;
344362 this . animatedOpacity . start ( ) ;
345363 }
@@ -356,6 +374,20 @@ class RNNDrawer {
356374 dispatch ( 'DRAWER_CLOSED' ) ;
357375 }
358376
377+ onOrientationChange = ( { window} : any ) => {
378+ const screenHeight = window . height ;
379+
380+ this . setState ( { screenHeight } ) ;
381+
382+ // Apply correct position if opened from right
383+ if ( this . props . direction === 'right' ) {
384+ // Calculates the position of the drawer from the left side of the screen
385+ const alignedMovementValue = window . width - this . drawerWidth ;
386+
387+ this . state . sideMenuOpenValue . setValue ( alignedMovementValue ) ;
388+ }
389+ }
390+
359391 /**
360392 * Registers all the listenrs for this component
361393 */
@@ -364,22 +396,13 @@ class RNNDrawer {
364396 const { direction, fadeOpacity } = this . props ;
365397
366398 // Adapt the drawer's size on orientation change
367- Dimensions . addEventListener ( 'change' , ( { window } ) => {
368- const screenHeight = window . height ;
369-
370- this . setState ( { screenHeight } ) ;
371-
372- // Apply correct position if opened from right
373- if ( this . props . direction === 'right' ) {
374- // Calculates the position of the drawer from the left side of the screen
375- const alignedMovementValue = window . width - this . drawerWidth ;
376-
377- this . state . sideMenuOpenValue . setValue ( alignedMovementValue ) ;
378- }
379- } ) ;
399+ Dimensions . addEventListener ( 'change' , this . onOrientationChange ) ;
380400
381401 // Executes when the side of the screen interaction starts
382- this . unsubscribeSwipeStart = listen ( 'SWIPE_START' , ( ) => {
402+ this . unsubscribeSwipeStart = listen ( 'SWIPE_START' , ( value : Point ) => {
403+ this . panningStartedPoint . moveX = value . moveX ;
404+ this . panningStartedPoint . moveY = value . moveY ;
405+
383406 this . setState ( {
384407 sideMenuSwipingStarted : true ,
385408 } ) ;
@@ -389,46 +412,62 @@ class RNNDrawer {
389412 this . unsubscribeSwipeMove = listen (
390413 'SWIPE_MOVE' ,
391414 ( { value, direction : swipeDirection } : SwipeMoveInterface ) => {
392- if ( swipeDirection === 'left' ) {
393- // Calculates the position of the drawer from the left side of the screen
394- const alignedMovementValue = value - this . drawerWidth ;
395- // Calculates the percetage 0 - 100 of which the drawer is open
396- const openedPercentage = Math . abs (
397- ( Math . abs ( alignedMovementValue ) / this . drawerWidth ) * 100 - 100 ,
398- ) ;
399- // Calculates the opacity to set of the screen based on the percentage the drawer is open
400- const normalizedOpacity = Math . min (
401- openedPercentage / 100 ,
402- fadeOpacity ,
403- ) ;
404-
405- // Does allow the drawer to go further than the maximum width
406- if ( this . drawerOpenedValues [ direction ] > alignedMovementValue ) {
407- // Sets the animation values, we use this so we can resume animation from any point
408- this . state . sideMenuOpenValue . setValue ( alignedMovementValue ) ;
415+ // Cover special case when we are swiping from the edge of the screen
416+ if ( this . startedFromSideMenu ) {
417+ if ( direction === "left" && value . moveX < this . drawerWidth ) {
418+ this . state . sideMenuOpenValue . setValue ( value . moveX - this . drawerWidth ) ;
419+ const normalizedOpacity = Math . min (
420+ ( value . moveX / this . drawerWidth ) * fadeOpacity ,
421+ fadeOpacity ,
422+ ) ;
409423 this . state . sideMenuOverlayOpacity . setValue ( normalizedOpacity ) ;
410424 }
425+ if ( direction === "right" && ( this . screenWidth - value . moveX ) < this . drawerWidth ) {
426+ this . state . sideMenuOpenValue . setValue ( value . moveX ) ;
427+ const normalizedOpacity = Math . min (
428+ ( ( this . screenWidth - value . moveX ) / this . drawerWidth ) * fadeOpacity ,
429+ fadeOpacity ,
430+ ) ;
431+ this . state . sideMenuOverlayOpacity . setValue ( normalizedOpacity ) ;
432+ }
433+
434+ return ;
435+ }
436+
437+ // Calculates the translateX / translateY value
438+ let alignedMovementValue = 0 ;
439+ // To swap the direction if needed
440+ let directionModifier = 1 ;
441+ // Whether we use the height of the drawer or the width
442+ let drawerDimension = this . drawerWidth ;
443+
444+ if ( swipeDirection === 'left' ) {
445+ alignedMovementValue = value . moveX - this . panningStartedPoint . moveX ;
411446 } else if ( swipeDirection === 'right' ) {
412- // Works out the distance from right of screen to the finger position
413- const normalizedValue = this . screenWidth - value ;
414- // Calculates the position of the drawer from the left side of the screen
415- const alignedMovementValue = this . screenWidth - normalizedValue ;
416- // Calculates the percetage 0 - 100 of which the drawer is open
417- const openedPercentage = Math . abs (
418- ( Math . abs ( normalizedValue ) / this . drawerWidth ) * 100 ,
419- ) ;
420- // Calculates the opacity to set of the screen based on the percentage the drawer is open
421- const normalizedOpacity = Math . min (
422- openedPercentage / 100 ,
447+ alignedMovementValue = this . panningStartedPoint . moveX - value . moveX ;
448+ directionModifier = - 1 ;
449+ } else if ( swipeDirection === 'bottom' ) {
450+ alignedMovementValue = this . panningStartedPoint . moveY - value . moveY ;
451+ directionModifier = - 1 ;
452+ drawerDimension = this . drawerHeight ;
453+ } else if ( swipeDirection === 'top' ) {
454+ alignedMovementValue = value . moveY - this . panningStartedPoint . moveY ;
455+ drawerDimension = this . drawerHeight ;
456+ }
457+
458+ // Calculates the percentage 0 - 1 of which the drawer is open
459+ const openedPercentage = Math . abs ( drawerDimension + alignedMovementValue ) / drawerDimension ;
460+ // Calculates the opacity to set of the screen based on the percentage the drawer is open
461+ const normalizedOpacity = Math . min (
462+ openedPercentage * fadeOpacity ,
423463 fadeOpacity ,
424- ) ;
464+ ) ;
425465
426- // Does allow the drawer to go further than the maximum width
427- if ( this . drawerOpenedValues [ direction ] < alignedMovementValue ) {
428- // Sets the animation values, we use this so we can resume animation from any point
429- this . state . sideMenuOpenValue . setValue ( alignedMovementValue ) ;
430- this . state . sideMenuOverlayOpacity . setValue ( normalizedOpacity ) ;
431- }
466+ // Does not allow the drawer to go further than the maximum width / height
467+ if ( 0 > alignedMovementValue ) {
468+ // Sets the animation values, we use this so we can resume animation from any point
469+ this . state . sideMenuOpenValue . setValue ( this . drawerOpenedValues [ direction ] + alignedMovementValue * directionModifier ) ;
470+ this . state . sideMenuOverlayOpacity . setValue ( normalizedOpacity ) ;
432471 }
433472 } ,
434473 ) ;
@@ -440,7 +479,11 @@ class RNNDrawer {
440479 const reverseDirection : DrawerReverseDirectionInterface = {
441480 right : 'left' ,
442481 left : 'right' ,
482+ top : 'bottom' ,
483+ bottom : 'top'
443484 } ;
485+ // In case the drawer started by dragging the edge of the screen reset the flag
486+ this . startedFromSideMenu = false ;
444487
445488 if ( swipeDirection === reverseDirection [ direction ] ) {
446489 this . animatedDrawer . start ( ) ;
@@ -472,7 +515,7 @@ class RNNDrawer {
472515 * Removes all the listenrs from this component
473516 */
474517 removeListeners ( ) {
475- Dimensions . removeEventListener ( 'change' , ( ) => { } ) ;
518+ Dimensions . removeEventListener ( 'change' , this . onOrientationChange ) ;
476519 if ( this . unsubscribeSwipeStart ) this . unsubscribeSwipeStart ( ) ;
477520 if ( this . unsubscribeSwipeMove ) this . unsubscribeSwipeMove ( ) ;
478521 if ( this . unsubscribeSwipeEnd ) this . unsubscribeSwipeEnd ( ) ;
@@ -494,8 +537,8 @@ class RNNDrawer {
494537 /** Variables */
495538 const animatedValue =
496539 direction === DirectionType . left || direction === DirectionType . right
497- ? { marginLeft : sideMenuOpenValue }
498- : { marginTop : sideMenuOpenValue } ;
540+ ? { translateX : sideMenuOpenValue }
541+ : { translateY : sideMenuOpenValue } ;
499542
500543 return (
501544 < View
@@ -517,7 +560,9 @@ class RNNDrawer {
517560 {
518561 height : this . state . screenHeight ,
519562 width : this . drawerWidth ,
520- ...animatedValue ,
563+ transform :[
564+ animatedValue
565+ ]
521566 } ,
522567 ] }
523568 >
@@ -547,15 +592,15 @@ class RNNDrawer {
547592 const closeValues : DrawerDirectionValuesInterface = {
548593 left : - this . drawerWidth ,
549594 right : this . screenWidth ,
550- top : - this . drawerHeight ,
595+ top : - this . screenHeight ,
551596 bottom : this . screenHeight ,
552597 } ;
553598
554599 // Animate side menu close
555600 Animated . timing ( this . state . sideMenuOpenValue , {
556601 toValue : closeValues [ direction ] ,
557602 duration : this . props . animationCloseTime ,
558- useNativeDriver : false ,
603+ useNativeDriver : true ,
559604 } ) . start ( ( ) => {
560605 Navigation . dismissOverlay ( this . props . componentId ) ;
561606 this . setState ( { sideMenuIsDismissing : false } ) ;
@@ -565,7 +610,7 @@ class RNNDrawer {
565610 Animated . timing ( this . state . sideMenuOverlayOpacity , {
566611 toValue : 0 ,
567612 duration : this . props . animationCloseTime ,
568- useNativeDriver : false ,
613+ useNativeDriver : true ,
569614 } ) . start ( ) ;
570615 }
571616 }
0 commit comments