Skip to content

Commit ccab7a3

Browse files
Inbal-Tishethanshar
authored andcommitted
Fix/drawer left toggle (#875)
* Fix left toggle drag threshold and haptic trigger timing; Add item reset position after left toggle * fix bounciness and closing of the drawer after item animation
1 parent 53ff001 commit ccab7a3

File tree

3 files changed

+61
-27
lines changed

3 files changed

+61
-27
lines changed

demo/src/screens/componentScreens/DrawerScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class DrawerScreen extends Component {
7878
};
7979

8080
toggleReadState = () => {
81-
this.setState({unread: !this.state.unread}); // setState will close the Drawer
81+
this.setState({unread: !this.state.unread});
8282
}
8383

8484
triggerLeftToggleHaptic = () => {

src/components/drawer/Swipeable.tsx

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,21 @@ export default class Swipeable extends Component<PropType, StateType> {
112112
_handleDrag = (e) => {
113113
const {onToggleSwipeLeft} = this.props;
114114

115-
if (onToggleSwipeLeft && !this.dragThresholdReached) {
115+
if (onToggleSwipeLeft) {
116+
// Drag left toggle
116117
const {rowWidth, leftWidth} = this.state;
117118
const x = e.nativeEvent.translationX;
118119
const threshold = rowWidth * LEFT_TOGGLE_THRESHOLD;
119-
if (x >= threshold && x < threshold + 10) {
120+
121+
if (!this.dragThresholdReached && x >= threshold && x < threshold + 10) {
122+
// move item right
120123
this.dragThresholdReached = true;
121-
onToggleSwipeLeft({rowWidth, leftWidth, dragX: x});
124+
onToggleSwipeLeft({rowWidth, leftWidth, dragX: x, triggerHaptic: true});
125+
}
126+
if (this.dragThresholdReached && x < threshold - 10) {
127+
// move item left
128+
this.dragThresholdReached = false;
129+
onToggleSwipeLeft({rowWidth, leftWidth, dragX: x, resetItemPosition: true});
122130
}
123131
}
124132
}
@@ -215,23 +223,32 @@ export default class Swipeable extends Component<PropType, StateType> {
215223
const {leftWidth = 0, rowWidth = 0} = this.state;
216224
const {rightOffset = rowWidth} = this.state;
217225
const rightWidth = rowWidth - rightOffset;
218-
const {fullSwipeLeft, fullSwipeRight, friction, leftThreshold = leftWidth / 2, rightThreshold = rightWidth / 2, fullLeftThreshold, fullRightThreshold, onToggleSwipeLeft} = this.props;
219-
226+
const {
227+
fullSwipeLeft,
228+
fullSwipeRight,
229+
friction,
230+
leftThreshold = leftWidth / 2,
231+
rightThreshold = rightWidth / 2,
232+
fullLeftThreshold,
233+
fullRightThreshold,
234+
onToggleSwipeLeft
235+
} = this.props;
220236
const startOffsetX = this._currentOffset() + dragX / friction;
221237
const translationX = (dragX + DRAG_TOSS * velocityX) / friction;
222238

223239
let toValue = 0;
224240
if (this.rowState === 0) {
225-
if (onToggleSwipeLeft && translationX > leftWidth) {
226-
if (!this.dragThresholdReached) {
227-
toValue = rowWidth * LEFT_TOGGLE_THRESHOLD;
228-
}
229-
} else if (fullSwipeLeft && translationX > rowWidth * fullLeftThreshold) {
241+
if (onToggleSwipeLeft && translationX > rowWidth * LEFT_TOGGLE_THRESHOLD && !this.dragThresholdReached) {
242+
// Swipe left toggle
243+
toValue = rowWidth * LEFT_TOGGLE_THRESHOLD;
244+
} else if (!onToggleSwipeLeft && fullSwipeLeft && translationX > rowWidth * fullLeftThreshold) {
230245
toValue = rowWidth;
231246
} else if (fullSwipeRight && translationX < -rowWidth * fullRightThreshold) {
232247
toValue = -rowWidth;
233248
} else if (translationX > leftThreshold) {
234-
toValue = leftWidth;
249+
if (!onToggleSwipeLeft || onToggleSwipeLeft && translationX < rowWidth * LEFT_TOGGLE_THRESHOLD) {
250+
toValue = leftWidth;
251+
}
235252
} else if (translationX < -rightThreshold) {
236253
toValue = -rightWidth;
237254
}
@@ -264,7 +281,6 @@ export default class Swipeable extends Component<PropType, StateType> {
264281
onSwipeableWillClose,
265282
onSwipeableWillOpen,
266283
onFullSwipeLeft,
267-
fullSwipeLeft,
268284
onToggleSwipeLeft,
269285
onWillFullSwipeLeft,
270286
onFullSwipeRight,
@@ -274,13 +290,13 @@ export default class Swipeable extends Component<PropType, StateType> {
274290
dragX.setValue(0);
275291
rowTranslation.setValue(fromValue);
276292
this.rowState = Math.sign(toValue);
277-
293+
278294
Animated.spring(rowTranslation, {
295+
toValue,
279296
restSpeedThreshold: 1.7,
280297
restDisplacementThreshold: 0.4,
281298
velocity: velocityX,
282299
bounciness: 0,
283-
toValue,
284300
useNativeDriver: useNativeAnimations,
285301
...animationOptions
286302
}).start(({finished}) => {
@@ -304,7 +320,8 @@ export default class Swipeable extends Component<PropType, StateType> {
304320
});
305321

306322
if ((toValue === rowWidth * LEFT_TOGGLE_THRESHOLD || this.dragThresholdReached) && onToggleSwipeLeft) {
307-
onToggleSwipeLeft({rowWidth, leftWidth, released: true});
323+
onToggleSwipeLeft({rowWidth, leftWidth, released: true, triggerHaptic: !this.dragThresholdReached});
324+
this.dragThresholdReached = false;
308325
} else if (toValue === rowWidth && onWillFullSwipeLeft) {
309326
onWillFullSwipeLeft()
310327
} else if (toValue === -rowWidth && onWillFullSwipeRight) {
@@ -350,6 +367,7 @@ export default class Swipeable extends Component<PropType, StateType> {
350367
};
351368

352369
toggleLeft = () => {
370+
// Programmatically left toggle
353371
const {rowWidth} = this.state;
354372
this._animateRow(this._currentOffset(), rowWidth * LEFT_TOGGLE_THRESHOLD);
355373
};

src/components/drawer/index.tsx

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import View from '../view';
1111
import Swipeable, {PropType as SwipeableProps} from './Swipeable';
1212

1313
const DEFAULT_BG = Colors.blue30;
14+
const DEFAULT_BOUNCINESS = 0;
1415

1516
interface ItemProps {
1617
width?: number;
@@ -123,7 +124,7 @@ class Drawer extends PureComponent<DrawerProps> {
123124
leftRender: SwipeableProps['renderLeftActions'];
124125
rightRender: SwipeableProps['renderLeftActions'];
125126
_swipeableRow: RefObject<Swipeable> = React.createRef();
126-
animationOptions: SwipeableProps['animationOptions'] = {bounciness: this.props.bounciness || 5};
127+
animationOptions: SwipeableProps['animationOptions'] = {bounciness: this.props.bounciness || DEFAULT_BOUNCINESS};
127128
leftActionX: Animated.Value = new Animated.Value(0);
128129

129130
constructor(props: DrawerProps) {
@@ -192,19 +193,34 @@ class Drawer extends PureComponent<DrawerProps> {
192193
_.invoke(this.props, 'onSwipeableWillClose', this.props);
193194
};
194195

195-
private onToggleSwipeLeft = ({rowWidth, leftWidth, dragX, released}: any) => {
196+
private onToggleSwipeLeft = (options?: any) => {
197+
if (this.props.onToggleSwipeLeft) {
198+
if (options?.triggerHaptic) {
199+
_.invoke(this.props, 'leftToggleHapticTrigger');
200+
}
201+
this.animateItem(options);
202+
}
203+
}
204+
205+
private animateItem({rowWidth, leftWidth, dragX, released, resetItemPosition}: any) {
206+
const toValue = resetItemPosition ? 0 : dragX ? dragX - leftWidth : rowWidth * 0.6 - leftWidth;
207+
196208
Animated.timing(this.leftActionX, {
197-
toValue: dragX ? dragX - leftWidth : rowWidth * 0.6 - leftWidth,
209+
toValue,
198210
easing: Easing.bezier(0.25, 1, 0.5, 1),
199211
duration: 200,
200212
delay: 100,
201213
useNativeDriver: true
202-
}).start(() => released && this.toggle());
203-
}
204-
205-
private toggle() {
206-
_.invoke(this.props, 'leftToggleHapticTrigger');
207-
_.invoke(this.props, 'onToggleSwipeLeft');
214+
}).start(() => {
215+
if (released) {
216+
// reset Drawer
217+
this.animateItem({released: false, resetItemPosition: true});
218+
this.closeDrawer();
219+
setTimeout(() => {
220+
_.invoke(this.props, 'onToggleSwipeLeft', this.props);
221+
}, 150);
222+
}
223+
});
208224
}
209225

210226
/** Accessability */
@@ -347,7 +363,7 @@ class Drawer extends PureComponent<DrawerProps> {
347363
};
348364

349365
render() {
350-
const {children, style, leftItem, rightItems, onToggleSwipeLeft, ...others} = this.props;
366+
const {children, style, leftItem, rightItems, ...others} = this.props;
351367

352368
return (
353369
<Swipeable
@@ -362,7 +378,7 @@ class Drawer extends PureComponent<DrawerProps> {
362378
leftActionsContainerStyle={this.getLeftActionsContainerStyle(leftItem, rightItems)}
363379
onSwipeableWillOpen={this.onSwipeableWillOpen}
364380
onSwipeableWillClose={this.onSwipeableWillClose}
365-
onToggleSwipeLeft={onToggleSwipeLeft && this.onToggleSwipeLeft}
381+
onToggleSwipeLeft={this.onToggleSwipeLeft}
366382
>
367383
<View
368384
// flex

0 commit comments

Comments
 (0)