@@ -78,9 +78,14 @@ export enum DirectionType {
78
78
top = 'top' ,
79
79
}
80
80
81
+ interface Point {
82
+ moveX : number ;
83
+ moveY : number ;
84
+ }
85
+
81
86
interface IState {
82
- sideMenuOpenValue : any ;
83
- sideMenuOverlayOpacity : any ;
87
+ sideMenuOpenValue : Animated . Value ;
88
+ sideMenuOverlayOpacity : Animated . Value ;
84
89
sideMenuSwipingStarted : boolean ;
85
90
sideMenuIsDismissing : boolean ;
86
91
screenHeight : number ;
@@ -97,6 +102,7 @@ interface IProps {
97
102
fadeOpacity : number ;
98
103
drawerScreenWidth : number | string ;
99
104
drawerScreenHeight : number | string ;
105
+ animateDrawerExpanding ?: boolean ;
100
106
style : any ;
101
107
}
102
108
@@ -124,7 +130,7 @@ interface DrawerReverseDirectionInterface {
124
130
}
125
131
126
132
interface SwipeMoveInterface {
127
- value : number ;
133
+ value : Point ;
128
134
direction : string ;
129
135
}
130
136
@@ -142,13 +148,16 @@ class RNNDrawer {
142
148
private readonly drawerWidth : number ;
143
149
private readonly drawerHeight : number ;
144
150
private readonly drawerOpenedValues : DrawerDirectionValuesInterface ;
151
+ private readonly initialValues : DrawerDirectionValuesInterface ;
145
152
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 ;
152
161
153
162
static defaultProps = {
154
163
animationOpenTime : 300 ,
@@ -158,6 +167,7 @@ class RNNDrawer {
158
167
fadeOpacity : 0.6 ,
159
168
drawerScreenWidth : '80%' ,
160
169
drawerScreenHeight : '100%' ,
170
+ animateDrawerExpanding : true
161
171
} ;
162
172
163
173
/**
@@ -186,9 +196,12 @@ class RNNDrawer {
186
196
_evt : GestureResponderEvent ,
187
197
_gestureState : PanResponderGestureState ,
188
198
) => {
189
- const { dx } = _gestureState ;
199
+ const { dx, dy } = _gestureState ;
190
200
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 ;
192
205
} ,
193
206
onMoveShouldSetPanResponderCapture : (
194
207
_evt : GestureResponderEvent ,
@@ -198,7 +211,9 @@ class RNNDrawer {
198
211
_evt : GestureResponderEvent ,
199
212
_gestureState : PanResponderGestureState ,
200
213
) => {
201
- dispatch ( 'SWIPE_START' ) ;
214
+ const { moveX, moveY } = _gestureState ;
215
+
216
+ dispatch ( 'SWIPE_START' , { moveX, moveY} ) ;
202
217
} ,
203
218
onPanResponderRelease : (
204
219
_evt : GestureResponderEvent ,
@@ -221,10 +236,10 @@ class RNNDrawer {
221
236
_evt : GestureResponderEvent ,
222
237
_gestureState : PanResponderGestureState ,
223
238
) => {
224
- const { moveX } = _gestureState ;
239
+ const { moveX, moveY } = _gestureState ;
225
240
const direction = this . props . direction || 'left' ;
226
241
227
- dispatch ( 'SWIPE_MOVE' , { value : moveX , direction } ) ;
242
+ dispatch ( 'SWIPE_MOVE' , { value : { moveX, moveY } , direction } ) ;
228
243
} ,
229
244
} ) ;
230
245
@@ -263,20 +278,20 @@ class RNNDrawer {
263
278
this . drawerOpenedValues = {
264
279
left : 0 ,
265
280
right : this . screenWidth - this . drawerWidth ,
266
- top : 0 ,
281
+ top : this . drawerHeight - this . screenHeight ,
267
282
bottom : this . screenHeight - this . drawerHeight ,
268
283
} ;
269
284
270
- const initialValues : DrawerDirectionValuesInterface = {
285
+ this . initialValues = {
271
286
left : - this . drawerWidth ,
272
287
right : this . screenWidth ,
273
- top : - this . drawerHeight ,
288
+ top : - this . screenHeight ,
274
289
bottom : this . screenHeight ,
275
290
} ;
276
291
277
292
/** Component State */
278
293
this . state = {
279
- sideMenuOpenValue : new Animated . Value ( initialValues [ props . direction ] ) ,
294
+ sideMenuOpenValue : new Animated . Value ( this . initialValues [ props . direction ] ) ,
280
295
sideMenuOverlayOpacity : new Animated . Value ( 0 ) ,
281
296
sideMenuSwipingStarted : false ,
282
297
sideMenuIsDismissing : false ,
@@ -310,13 +325,16 @@ class RNNDrawer {
310
325
*/
311
326
componentDidMount ( ) {
312
327
/** 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 ;
314
332
315
333
// Animate side menu open
316
334
this . animatedDrawer = Animated . timing ( this . state . sideMenuOpenValue , {
317
335
toValue : this . drawerOpenedValues [ direction ] ,
318
336
duration : this . props . animationOpenTime ,
319
- useNativeDriver : false ,
337
+ useNativeDriver : true ,
320
338
} ) ;
321
339
322
340
// Animate outside side menu opacity
@@ -325,7 +343,7 @@ class RNNDrawer {
325
343
{
326
344
toValue : fadeOpacity ,
327
345
duration : this . props . animationOpenTime ,
328
- useNativeDriver : false ,
346
+ useNativeDriver : true ,
329
347
} ,
330
348
) ;
331
349
}
@@ -339,7 +357,7 @@ class RNNDrawer {
339
357
this . registerListeners ( ) ;
340
358
341
359
// 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 ) {
343
361
this . animatedDrawer . start ( ) ;
344
362
this . animatedOpacity . start ( ) ;
345
363
}
@@ -356,6 +374,20 @@ class RNNDrawer {
356
374
dispatch ( 'DRAWER_CLOSED' ) ;
357
375
}
358
376
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
+
359
391
/**
360
392
* Registers all the listenrs for this component
361
393
*/
@@ -364,22 +396,13 @@ class RNNDrawer {
364
396
const { direction, fadeOpacity } = this . props ;
365
397
366
398
// 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 ) ;
380
400
381
401
// 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
+
383
406
this . setState ( {
384
407
sideMenuSwipingStarted : true ,
385
408
} ) ;
@@ -389,46 +412,62 @@ class RNNDrawer {
389
412
this . unsubscribeSwipeMove = listen (
390
413
'SWIPE_MOVE' ,
391
414
( { 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
+ ) ;
409
423
this . state . sideMenuOverlayOpacity . setValue ( normalizedOpacity ) ;
410
424
}
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 ;
411
446
} 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 ,
423
463
fadeOpacity ,
424
- ) ;
464
+ ) ;
425
465
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 ) ;
432
471
}
433
472
} ,
434
473
) ;
@@ -440,7 +479,11 @@ class RNNDrawer {
440
479
const reverseDirection : DrawerReverseDirectionInterface = {
441
480
right : 'left' ,
442
481
left : 'right' ,
482
+ top : 'bottom' ,
483
+ bottom : 'top'
443
484
} ;
485
+ // In case the drawer started by dragging the edge of the screen reset the flag
486
+ this . startedFromSideMenu = false ;
444
487
445
488
if ( swipeDirection === reverseDirection [ direction ] ) {
446
489
this . animatedDrawer . start ( ) ;
@@ -472,7 +515,7 @@ class RNNDrawer {
472
515
* Removes all the listenrs from this component
473
516
*/
474
517
removeListeners ( ) {
475
- Dimensions . removeEventListener ( 'change' , ( ) => { } ) ;
518
+ Dimensions . removeEventListener ( 'change' , this . onOrientationChange ) ;
476
519
if ( this . unsubscribeSwipeStart ) this . unsubscribeSwipeStart ( ) ;
477
520
if ( this . unsubscribeSwipeMove ) this . unsubscribeSwipeMove ( ) ;
478
521
if ( this . unsubscribeSwipeEnd ) this . unsubscribeSwipeEnd ( ) ;
@@ -494,8 +537,8 @@ class RNNDrawer {
494
537
/** Variables */
495
538
const animatedValue =
496
539
direction === DirectionType . left || direction === DirectionType . right
497
- ? { marginLeft : sideMenuOpenValue }
498
- : { marginTop : sideMenuOpenValue } ;
540
+ ? { translateX : sideMenuOpenValue }
541
+ : { translateY : sideMenuOpenValue } ;
499
542
500
543
return (
501
544
< View
@@ -517,7 +560,9 @@ class RNNDrawer {
517
560
{
518
561
height : this . state . screenHeight ,
519
562
width : this . drawerWidth ,
520
- ...animatedValue ,
563
+ transform :[
564
+ animatedValue
565
+ ]
521
566
} ,
522
567
] }
523
568
>
@@ -547,15 +592,15 @@ class RNNDrawer {
547
592
const closeValues : DrawerDirectionValuesInterface = {
548
593
left : - this . drawerWidth ,
549
594
right : this . screenWidth ,
550
- top : - this . drawerHeight ,
595
+ top : - this . screenHeight ,
551
596
bottom : this . screenHeight ,
552
597
} ;
553
598
554
599
// Animate side menu close
555
600
Animated . timing ( this . state . sideMenuOpenValue , {
556
601
toValue : closeValues [ direction ] ,
557
602
duration : this . props . animationCloseTime ,
558
- useNativeDriver : false ,
603
+ useNativeDriver : true ,
559
604
} ) . start ( ( ) => {
560
605
Navigation . dismissOverlay ( this . props . componentId ) ;
561
606
this . setState ( { sideMenuIsDismissing : false } ) ;
@@ -565,7 +610,7 @@ class RNNDrawer {
565
610
Animated . timing ( this . state . sideMenuOverlayOpacity , {
566
611
toValue : 0 ,
567
612
duration : this . props . animationCloseTime ,
568
- useNativeDriver : false ,
613
+ useNativeDriver : true ,
569
614
} ) . start ( ) ;
570
615
}
571
616
}
0 commit comments