Skip to content

Commit fbc8f8c

Browse files
committed
Fix drawer scrolling issue when drawer close
Fix drawer scrolling issue when drawer close
1 parent 5bcaba4 commit fbc8f8c

File tree

1 file changed

+84
-87
lines changed

1 file changed

+84
-87
lines changed

src/Drawer.js

Lines changed: 84 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,14 @@ import {
99
StatusBar,
1010
Text,
1111
TouchableWithoutFeedback,
12-
View
12+
View,
1313
} from 'react-native';
1414
import Icon from 'react-native-vector-icons/Ionicons';
15-
import ExtraDimensions from 'react-native-extra-dimensions-android';
1615

1716
// Get screen dimensions
18-
const { width } = Dimensions.get('window');
19-
const height = Platform.OS === 'ios' ? Dimensions.get('screen').height : Dimensions.get('screen').height - ExtraDimensions.get('SOFT_MENU_BAR_HEIGHT');
17+
const { width, height } = Dimensions.get('window');
2018

2119
export default class Drawer extends Component {
22-
2320
// Define prop types
2421
static propTypes = {
2522
// Pass messages to show as children
@@ -32,7 +29,6 @@ export default class Drawer extends Component {
3229
headerHeight: PropTypes.number,
3330
// Height of the visible teaser area at the bottom of the screen
3431
teaserHeight: PropTypes.number,
35-
onClose: PropTypes.func,
3632
};
3733

3834
// Set default prop values
@@ -41,7 +37,6 @@ export default class Drawer extends Component {
4137
header: 'Messages',
4238
headerHeight: 70,
4339
teaserHeight: 75,
44-
onClose:()=>{}
4540
};
4641

4742
// Define state
@@ -67,20 +62,17 @@ export default class Drawer extends Component {
6762
// minimal possible value - a bit lower the top of the screen
6863
min: this.props.headerHeight,
6964
// When animated triggers these value updates
70-
animates: [
71-
() => this._animatedOpacity,
72-
() => this._animatedWidth
73-
]
65+
animates: [() => this._animatedOpacity, () => this._animatedWidth],
7466
},
7567
// Window width
7668
width: {
77-
end: width, // takes full with once opened
78-
start: width - 20, // slightly narrower than screen when closed
69+
end: width, // takes full with once opened
70+
start: width - 20, // slightly narrower than screen when closed
7971
},
8072
// Window backdrop opacity
8173
opacity: {
82-
start: 0, // fully transparent when closed
83-
end: 1 // not transparent once opened
74+
start: 0, // fully transparent when closed
75+
end: 1, // not transparent once opened
8476
},
8577
};
8678

@@ -94,9 +86,9 @@ export default class Drawer extends Component {
9486
_animatedWidth = new Animated.Value(this.config.width.start);
9587

9688
// Animates window position
97-
_animatedPosition = new Animated.Value(this.props.isOpen
98-
? this.config.position.end
99-
: this.config.position.start);
89+
_animatedPosition = new Animated.Value(
90+
this.props.isOpen ? this.config.position.end : this.config.position.start,
91+
);
10092

10193
componentWillMount() {
10294
// Set current position
@@ -106,9 +98,9 @@ export default class Drawer extends Component {
10698
// Update _currentPosition
10799
this._currentPosition = value.value;
108100
// Animate depending values
109-
this.config.position.animates.map(item => {
101+
this.config.position.animates.map((item) => {
110102
item().setValue(value.value);
111-
})
103+
});
112104
});
113105
// Reset value once listener is registered to update depending animations
114106
this._animatedPosition.setValue(this._animatedPosition._value);
@@ -132,9 +124,8 @@ export default class Drawer extends Component {
132124
// isOpen prop changed to true from false
133125
if (!this.props.isOpen && nextProps.isOpen) {
134126
this.open();
135-
}
136-
// isOpen prop changed to false from true
137-
else if (this.props.isOpen && !nextProps.isOpen) {
127+
} else if (this.props.isOpen && !nextProps.isOpen) {
128+
// isOpen prop changed to false from true
138129
this.close();
139130
}
140131
}
@@ -148,21 +139,23 @@ export default class Drawer extends Component {
148139
}),
149140
// Interpolate position value into width value
150141
animatedWidth = this._animatedWidth.interpolate({
151-
inputRange: [this.config.position.min,// top of the screen
152-
this.config.position.start - 50, // 50 pixels higher than next point
153-
this.config.position.start, // a bit higher than the bottom of the screen
154-
this.config.position.max // the bottom of the screen
142+
inputRange: [
143+
this.config.position.min, // top of the screen
144+
this.config.position.start - 50, // 50 pixels higher than next point
145+
this.config.position.start, // a bit higher than the bottom of the screen
146+
this.config.position.max, // the bottom of the screen
155147
],
156-
outputRange: [this.config.width.end, // keep max width after next point
157-
this.config.width.end, // end: max width at 50 pixel higher
158-
this.config.width.start, // start: min width at the bottom
159-
this.config.width.start // keep min width before previous point
148+
outputRange: [
149+
this.config.width.end, // keep max width after next point
150+
this.config.width.end, // end: max width at 50 pixel higher
151+
this.config.width.start, // start: min width at the bottom
152+
this.config.width.start, // keep min width before previous point
160153
],
161154
});
162155
return (
163156
<Animated.View style={[styles.container, this.getContainerStyle()]}>
164157
{/* Use light status bar because we have dark background */}
165-
<StatusBar barStyle={"light-content"} />
158+
<StatusBar barStyle={'light-content'} />
166159
{/* Backdrop with animated opacity */}
167160
<Animated.View style={[styles.backdrop, { opacity: animatedOpacity }]}>
168161
{/* Close window when tapped on header */}
@@ -181,20 +174,28 @@ export default class Drawer extends Component {
181174
</Animated.View>
182175
{/* Content container */}
183176
<Animated.View
184-
style={[styles.content, {
185-
// Add padding at the bottom to fit all content on the screen
186-
paddingBottom: this.props.headerHeight,
187-
// Animate width
188-
width: animatedWidth,
189-
// Animate position on the screen
190-
transform: [{ translateY: this._animatedPosition }, { translateX: 0 }]
191-
}]}
177+
style={[
178+
styles.content,
179+
{
180+
// Add padding at the bottom to fit all content on the screen
181+
paddingBottom: this.props.headerHeight,
182+
// Animate width
183+
width: animatedWidth,
184+
// Animate position on the screen
185+
transform: [
186+
{ translateY: this._animatedPosition },
187+
{ translateX: 0 },
188+
],
189+
},
190+
]}
192191
// Handle gestures
193192
{...this._panResponder.panHandlers}
194193
>
195194
{/* Put all content in a scrollable container */}
196195
<ScrollView
197-
ref={(scrollView) => { this._scrollView = scrollView; }}
196+
ref={(scrollView) => {
197+
this._scrollView = scrollView;
198+
}}
198199
// Enable scrolling only when the window is open
199200
scrollEnabled={this.state.open}
200201
// Hide all scrolling indicators
@@ -217,13 +218,11 @@ export default class Drawer extends Component {
217218
// Allow if is not open
218219
if (!this.state.open) {
219220
return true;
220-
}
221-
// Allow if user haven't scroll the content yet
222-
else if (this.pulledDown(gestureState) && this.state.scrollOffset <= 0) {
221+
} else if (this.pulledDown(gestureState) && this.state.scrollOffset <= 0) {
222+
// Allow if user haven't scroll the content yet
223223
return true;
224-
}
225-
// Allow if pulled down rapidly
226-
else if (this.pulledDown(gestureState) && this.pulledFast(gestureState)) {
224+
} else if (this.pulledDown(gestureState) && this.pulledFast(gestureState)) {
225+
// Allow if pulled down rapidly
227226
return true;
228227
}
229228
// Deny otherwise
@@ -257,46 +256,42 @@ export default class Drawer extends Component {
257256
// Pulled down and far enough to trigger close
258257
if (this.pulledDown(gestureState) && this.pulledFar(gestureState)) {
259258
return this.close();
260-
}
261-
// Pulled up and far enough to trigger open
262-
else if (this.pulledUp(gestureState) && this.pulledFar(gestureState)) {
259+
} else if (this.pulledUp(gestureState) && this.pulledFar(gestureState)) {
260+
// Pulled up and far enough to trigger open
263261
return this.open();
264-
}
265-
// Toggle if tapped
266-
else if (this.tapped(gestureState)) {
262+
} else if (this.tapped(gestureState)) {
263+
// Toggle if tapped
267264
return this.toggle();
268265
}
269266
// Restore back to appropriate position otherwise
270-
else {
271-
this.restore();
272-
}
267+
this.restore();
273268
};
274269

275270
// Handle content scrolling
276-
_handleScroll = event => {
271+
_handleScroll = (event) => {
277272
const { y } = event.nativeEvent.contentOffset;
278273
this.setState({ scrollOffset: y });
279274
};
280275

281276
// Check if gesture was a tap
282-
tapped = (gestureState) => gestureState.dx === 0 && gestureState.dy === 0;
277+
tapped = gestureState => gestureState.dx === 0 && gestureState.dy === 0;
283278

284279
// Check if pulled up
285-
pulledUp = (gestureState) => gestureState.dy < 0;
280+
pulledUp = gestureState => gestureState.dy < 0;
286281

287282
// Check if pulled down
288-
pulledDown = (gestureState) => gestureState.dy > 0;
283+
pulledDown = gestureState => gestureState.dy > 0;
289284

290285
// Check if pulled rapidly
291-
pulledFast = (gestureState) => Math.abs(gestureState.vy) > 0.75;
286+
pulledFast = gestureState => Math.abs(gestureState.vy) > 0.75;
292287

293288
// Check if pulled far
294-
pulledFar = (gestureState) => Math.abs(gestureState.dy) > 50;
289+
pulledFar = gestureState => Math.abs(gestureState.dy) > 50;
295290

296291
// Check if current position is inside allowed range
297292
insideAllowedRange = () =>
298-
this._currentPosition >= this.config.position.min
299-
&& this._currentPosition <= this.config.position.max;
293+
this._currentPosition >= this.config.position.min &&
294+
this._currentPosition <= this.config.position.max;
300295

301296
// Open up the window on full screen
302297
open = () => {
@@ -310,22 +305,24 @@ export default class Drawer extends Component {
310305

311306
// Minimize window and keep a teaser at the bottom
312307
close = () => {
313-
this.props.onClose();
314308
this._scrollView.scrollTo({ y: 0 });
315309
Animated.timing(this._animatedPosition, {
316310
toValue: this.config.position.start,
317311
duration: 400,
318-
}).start(() => this.setState({
319-
open: false,
320-
}));
312+
}).start(() => {
313+
this.setState({
314+
open: false,
315+
});
316+
317+
this._scrollView.scrollTo({ y: 0 });
318+
});
321319
};
322320

323321
// Toggle window state between opened and closed
324322
toggle = () => {
325323
if (!this.state.open) {
326324
this.open();
327-
}
328-
else {
325+
} else {
329326
this.close();
330327
}
331328
};
@@ -334,17 +331,17 @@ export default class Drawer extends Component {
334331
restore = () => {
335332
if (this.state.open) {
336333
this.open();
337-
}
338-
else {
334+
} else {
339335
this.close();
340336
}
341337
};
342338

343339
// Get header style
344340
getHeaderStyle = () => ({
345-
height: Platform.OS === 'ios'
346-
? this.props.headerHeight
347-
: this.props.headerHeight - 40, // compensate for the status bar
341+
height:
342+
Platform.OS === 'ios'
343+
? this.props.headerHeight
344+
: this.props.headerHeight - 40, // compensate for the status bar
348345
});
349346

350347
// Get container style
@@ -358,36 +355,36 @@ export default class Drawer extends Component {
358355
const styles = StyleSheet.create({
359356
// Main container
360357
container: {
361-
...StyleSheet.absoluteFillObject, // fill up all screen
362-
alignItems: 'center', // center children
363-
justifyContent: 'flex-end', // align popup at the bottom
364-
backgroundColor: 'transparent', // transparent background
365-
elevation: 999, // fix android dynamic zindex issue
358+
...StyleSheet.absoluteFillObject, // fill up all screen
359+
alignItems: 'center', // center children
360+
justifyContent: 'flex-end', // align popup at the bottom
361+
backgroundColor: 'transparent', // transparent background
362+
elevation: 999, // fix android dynamic zindex issue
366363
},
367364
// Semi-transparent background below popup
368365
backdrop: {
369-
...StyleSheet.absoluteFillObject, // fill up all screen
370-
alignItems: 'center', // center children
371-
justifyContent: 'flex-start', // align popup at the bottom
366+
...StyleSheet.absoluteFillObject, // fill up all screen
367+
alignItems: 'center', // center children
368+
justifyContent: 'flex-start', // align popup at the bottom
372369
backgroundColor: 'black',
373370
},
374371
// Body
375372
content: {
376373
backgroundColor: 'black',
377-
height: height,
374+
height,
378375
},
379376
// Header
380377
header: {
381-
flexDirection: 'row', // arrange children in a row
382-
alignItems: 'center', // center vertically
378+
flexDirection: 'row', // arrange children in a row
379+
alignItems: 'center', // center vertically
383380
paddingTop: 20,
384381
paddingHorizontal: 20,
385382
},
386383
headerIcon: {
387384
marginRight: 10,
388385
},
389386
headerTitle: {
390-
flex: 1, // take up all available space
387+
flex: 1, // take up all available space
391388
},
392389
headerText: {
393390
color: 'white',

0 commit comments

Comments
 (0)