Skip to content

Commit 00f29ab

Browse files
M-i-k-e-lethanshar
authored andcommitted
Feat/panning fixes (#483)
* Reset swipe after a drag has occurred (and allow swipe after a canceled swipe) * Fix animateDismiss not coming through if mid animation * Do not expose maximumDragsAfterSwipe * Renaming * Remove shouldDismissAfterReset from the state * Add documentation * Fix lint errors
1 parent 62d1afa commit 00f29ab

File tree

3 files changed

+44
-23
lines changed

3 files changed

+44
-23
lines changed

src/components/dialog/index.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@ import View from '../view';
1111
import PanGestureView from '../panningViews/panGestureView';
1212

1313

14-
/*eslint-disable*/
1514
/**
1615
* @description: Dialog component for displaying custom content inside a popup dialog
17-
* @notes: Use alignment modifiers to control the dialog positon (top, bottom, centerV, centerH, etc... by default the dialog is align to center)
16+
* @notes: Use alignment modifiers to control the dialog position
17+
* (top, bottom, centerV, centerH, etc... by default the dialog is aligned to center)
1818
* @modifiers: alignment
1919
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/DialogScreen.js
2020
* @gif: https://media.giphy.com/media/9S58XdLCoUiLzAc1b1/giphy.gif
2121
*/
22-
/*eslint-enable*/
2322

2423
const SWIPE_DIRECTIONS = {
2524
UP: 'up',

src/components/panningViews/panDismissibleView.js

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ import PanningProvider from './panningProvider';
99
const DEFAULT_SPEED = 20;
1010
const DEFAULT_BOUNCINESS = 6;
1111
const DEFAULT_DISMISS_ANIMATION_DURATION = 280;
12+
const MAXIMUM_DRAGS_AFTER_SWIPE = 2;
1213

1314
/**
1415
* @description: PanDismissibleView component created to making listening to swipe and drag events easier,
15-
* Has to be used as a child of a PanningProvider that also has a PanListenerView
16+
* @notes: Has to be used as a child of a PanningProvider that also has a PanListenerView.
17+
* The PanListenerView is the one that sends the drag\swipe events.
1618
*/
1719
class PanDismissibleView extends PureComponent {
1820
static displayName = 'PanDismissibleView';
@@ -60,8 +62,9 @@ class PanDismissibleView extends PureComponent {
6062
this.state = {
6163
animTranslateX: new Animated.Value(0),
6264
animTranslateY: new Animated.Value(0),
63-
isAnimating: false,
65+
isAnimating: false
6466
};
67+
shouldDismissAfterReset = false;
6568
this.ref = React.createRef();
6669
}
6770

@@ -110,22 +113,31 @@ class PanDismissibleView extends PureComponent {
110113
}
111114
};
112115

113-
initPositions = () => {
116+
initPositions = (extraDataForSetState, runAfterSetState) => {
114117
this.setNativeProps(0, 0);
115118
this.setState({
116119
animTranslateX: new Animated.Value(0),
117120
animTranslateY: new Animated.Value(0),
118-
});
121+
...extraDataForSetState
122+
}, runAfterSetState);
119123
};
120124

121125
onPanStart = () => {
122126
this.swipe = {};
127+
this.counter = 0;
123128
};
124129

125130
onDrag = deltas => {
126131
const left = deltas.x ? Math.round(deltas.x) : 0;
127132
const top = deltas.y ? Math.round(deltas.y) : 0;
128133
this.setNativeProps(left, top);
134+
if (this.swipe.x || this.swipe.y) {
135+
if (this.counter < MAXIMUM_DRAGS_AFTER_SWIPE) {
136+
this.counter += 1;
137+
} else {
138+
this.swipe = {};
139+
}
140+
}
129141
};
130142

131143
setNativeProps = (left, top) => {
@@ -156,12 +168,12 @@ class PanDismissibleView extends PureComponent {
156168
const {isRight, isDown} = this.getDismissAnimationDirection();
157169
this._animateDismiss(isRight, isDown);
158170
} else {
159-
this.animateToInitialPosition();
171+
this.resetPosition();
160172
}
161173
}
162174
};
163175

164-
animateToInitialPosition = () => {
176+
resetPosition = () => {
165177
const {animTranslateX, animTranslateY} = this.state;
166178
const {speed, bounciness} = this.props.animationOptions;
167179
const toX = -this.left;
@@ -188,13 +200,14 @@ class PanDismissibleView extends PureComponent {
188200
}
189201

190202
this.setState({isAnimating: true}, () => {
191-
Animated.parallel(animations).start(this.onInitAnimationFinished);
203+
Animated.parallel(animations).start(this.onResetPositionFinished);
192204
});
193205
};
194206

195-
onInitAnimationFinished = () => {
196-
this.setState({isAnimating: false});
197-
this.initPositions();
207+
onResetPositionFinished = () => {
208+
const runAfterSetState = this.shouldDismissAfterReset ? this.animateDismiss : undefined;
209+
this.shouldDismissAfterReset = false;
210+
this.initPositions({isAnimating: false}, runAfterSetState);
198211
};
199212

200213
getDismissAnimationDirection = () => {
@@ -232,14 +245,19 @@ class PanDismissibleView extends PureComponent {
232245
// isDown === true --> animate to the bottom
233246
// isDown === false --> animate to the top
234247
animateDismiss = () => {
235-
const {directions = []} = this.props;
236-
const hasUp = directions.includes(PanningProvider.Directions.UP);
237-
const hasRight = directions.includes(PanningProvider.Directions.RIGHT);
238-
const hasLeft = directions.includes(PanningProvider.Directions.LEFT);
239-
const hasDown = !hasUp && !hasLeft && !hasRight; // default
240-
const verticalDismiss = hasDown ? true : hasUp ? false : undefined;
241-
const horizontalDismiss = hasRight ? true : hasLeft ? false : undefined;
242-
this._animateDismiss(horizontalDismiss, verticalDismiss);
248+
const {isAnimating} = this.state;
249+
if (isAnimating) {
250+
this.shouldDismissAfterReset = true;
251+
} else {
252+
const {directions = []} = this.props;
253+
const hasUp = directions.includes(PanningProvider.Directions.UP);
254+
const hasRight = directions.includes(PanningProvider.Directions.RIGHT);
255+
const hasLeft = directions.includes(PanningProvider.Directions.LEFT);
256+
const hasDown = !hasUp && !hasLeft && !hasRight; // default
257+
const verticalDismiss = hasDown ? true : hasUp ? false : undefined;
258+
const horizontalDismiss = hasRight ? true : hasLeft ? false : undefined;
259+
this._animateDismiss(horizontalDismiss, verticalDismiss);
260+
}
243261
};
244262

245263
_animateDismiss = (isRight, isDown) => {

src/components/panningViews/panningProvider.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ const DIRECTIONS = {
88
RIGHT: 'right',
99
};
1010

11+
/**
12+
* @description: Wraps the panDismissibleView and panListenerView to provide a shared context
13+
*/
1114
export default class PanningProvider extends Component {
15+
static displayName = 'PanningProvider'
1216
static Directions = DIRECTIONS;
1317

1418
constructor(props) {
@@ -55,11 +59,11 @@ export default class PanningProvider extends Component {
5559
};
5660

5761
onDrag = ({directions, deltas}) => {
58-
this.setState({dragDirections: directions, dragDeltas: deltas});
62+
this.setState({dragDirections: directions, dragDeltas: deltas, swipeDirections: {}, swipeVelocities: {}});
5963
};
6064

6165
onSwipe = ({directions, velocities}) => {
62-
this.setState({swipeDirections: directions, swipeVelocities: velocities});
66+
this.setState({swipeDirections: directions, swipeVelocities: velocities, dragDirections: {}, dragDeltas: {}});
6367
};
6468

6569
render() {

0 commit comments

Comments
 (0)