diff --git a/src/Drawer.js b/src/Drawer.js
index 20f5e04..23865eb 100644
--- a/src/Drawer.js
+++ b/src/Drawer.js
@@ -1,4 +1,4 @@
-import React, { Component, PropTypes } from 'react';
+import React, { Component, PropTypes } from "react";
import {
Animated,
Dimensions,
@@ -10,14 +10,13 @@ import {
Text,
TouchableWithoutFeedback,
View
-} from 'react-native';
-import Icon from 'react-native-vector-icons/Ionicons';
+} from "react-native";
+import Icon from "react-native-vector-icons/Ionicons";
// Get screen dimensions
-const { width, height } = Dimensions.get('window');
+const { width, height } = Dimensions.get("window");
export default class Drawer extends Component {
-
// Define prop types
static propTypes = {
// Pass messages to show as children
@@ -29,15 +28,15 @@ export default class Drawer extends Component {
// Header height
headerHeight: PropTypes.number,
// Height of the visible teaser area at the bottom of the screen
- teaserHeight: PropTypes.number,
+ teaserHeight: PropTypes.number
};
// Set default prop values
static defaultProps = {
isOpen: false,
- header: 'Messages',
+ header: "Messages",
headerHeight: 70,
- teaserHeight: 75,
+ teaserHeight: 75
};
// Define state
@@ -47,7 +46,7 @@ export default class Drawer extends Component {
// Whether the window is being pulled up/down or not
pulling: false,
// Zero means user haven't scrolled the content yet
- scrollOffset: 0,
+ scrollOffset: 0
};
// Configure animations
@@ -63,21 +62,18 @@ export default class Drawer extends Component {
// minimal possible value - a bit lower the top of the screen
min: this.props.headerHeight,
// When animated triggers these value updates
- animates: [
- () => this._animatedOpacity,
- () => this._animatedWidth
- ]
+ animates: [() => this._animatedOpacity, () => this._animatedWidth]
},
// Window width
width: {
- end: width, // takes full with once opened
- start: width - 20, // slightly narrower than screen when closed
+ end: width, // takes full with once opened
+ start: width - 20 // slightly narrower than screen when closed
},
// Window backdrop opacity
opacity: {
- start: 0, // fully transparent when closed
- end: 1 // not transparent once opened
- },
+ start: 0, // fully transparent when closed
+ end: 1 // not transparent once opened
+ }
};
// Pan responder to handle gestures
@@ -90,21 +86,21 @@ export default class Drawer extends Component {
_animatedWidth = new Animated.Value(this.config.width.start);
// Animates window position
- _animatedPosition = new Animated.Value(this.props.isOpen
- ? this.config.position.end
- : this.config.position.start);
+ _animatedPosition = new Animated.Value(
+ this.props.isOpen ? this.config.position.end : this.config.position.start
+ );
componentWillMount() {
// Set current position
this._currentPosition = this._animatedPosition._value;
// Listen for this._animatedPosition changes
- this._animatedPosition.addListener((value) => {
+ this._animatedPosition.addListener(value => {
// Update _currentPosition
this._currentPosition = value.value;
// Animate depending values
this.config.position.animates.map(item => {
item().setValue(value.value);
- })
+ });
});
// Reset value once listener is registered to update depending animations
this._animatedPosition.setValue(this._animatedPosition._value);
@@ -119,7 +115,7 @@ export default class Drawer extends Component {
onPanResponderTerminationRequest: (evt, gestureState) => true,
onPanResponderRelease: this._handlePanResponderEnd,
onPanResponderTerminate: this._handlePanResponderEnd,
- onShouldBlockNativeResponder: (evt, gestureState) => true,
+ onShouldBlockNativeResponder: (evt, gestureState) => true
});
}
@@ -128,9 +124,8 @@ export default class Drawer extends Component {
// isOpen prop changed to true from false
if (!this.props.isOpen && nextProps.isOpen) {
this.open();
- }
- // isOpen prop changed to false from true
- else if (this.props.isOpen && !nextProps.isOpen) {
+ } else if (this.props.isOpen && !nextProps.isOpen) {
+ // isOpen prop changed to false from true
this.close();
}
}
@@ -140,20 +135,22 @@ export default class Drawer extends Component {
// Interpolate position value into opacity value
animatedOpacity = this._animatedOpacity.interpolate({
inputRange: [this.config.position.end, this.config.position.start],
- outputRange: [this.config.opacity.end, this.config.opacity.start],
+ outputRange: [this.config.opacity.end, this.config.opacity.start]
}),
// Interpolate position value into width value
animatedWidth = this._animatedWidth.interpolate({
- inputRange: [this.config.position.min,// top of the screen
- this.config.position.start - 50, // 50 pixels higher than next point
- this.config.position.start, // a bit higher than the bottom of the screen
- this.config.position.max // the bottom of the screen
- ],
- outputRange: [this.config.width.end, // keep max width after next point
- this.config.width.end, // end: max width at 50 pixel higher
- this.config.width.start, // start: min width at the bottom
- this.config.width.start // keep min width before previous point
+ inputRange: [
+ this.config.position.min, // top of the screen
+ this.config.position.start - 50, // 50 pixels higher than next point
+ this.config.position.start, // a bit higher than the bottom of the screen
+ this.config.position.max // the bottom of the screen
],
+ outputRange: [
+ this.config.width.end, // keep max width after next point
+ this.config.width.end, // end: max width at 50 pixel higher
+ this.config.width.start, // start: min width at the bottom
+ this.config.width.start // keep min width before previous point
+ ]
});
return (
@@ -177,20 +174,28 @@ export default class Drawer extends Component {
{/* Content container */}
{/* Put all content in a scrollable container */}
{ this._scrollView = scrollView; }}
+ ref={scrollView => {
+ this._scrollView = scrollView;
+ }}
// Enable scrolling only when the window is open
scrollEnabled={this.state.open}
// Hide all scrolling indicators
@@ -213,13 +218,11 @@ export default class Drawer extends Component {
// Allow if is not open
if (!this.state.open) {
return true;
- }
- // Allow if user haven't scroll the content yet
- else if (this.pulledDown(gestureState) && this.state.scrollOffset <= 0) {
+ } else if (this.pulledDown(gestureState) && this.state.scrollOffset <= 0) {
+ // Allow if user haven't scroll the content yet
return true;
- }
- // Allow if pulled down rapidly
- else if (this.pulledDown(gestureState) && this.pulledFast(gestureState)) {
+ } else if (this.pulledDown(gestureState) && this.pulledFast(gestureState)) {
+ // Allow if pulled down rapidly
return true;
}
// Deny otherwise
@@ -246,6 +249,7 @@ export default class Drawer extends Component {
// Called when gesture ended
_handlePanResponderEnd = (evt, gestureState) => {
+ console.log(gestureState);
// Reset offset
this._animatedPosition.flattenOffset();
// Reset pulling state
@@ -253,19 +257,18 @@ export default class Drawer extends Component {
// Pulled down and far enough to trigger close
if (this.pulledDown(gestureState) && this.pulledFar(gestureState)) {
return this.close();
- }
- // Pulled up and far enough to trigger open
- else if (this.pulledUp(gestureState) && this.pulledFar(gestureState)) {
+ } else if (this.pulledUp(gestureState) && this.pulledFar(gestureState)) {
+ // Pulled up and far enough to trigger open
return this.open();
- }
- // Toggle if tapped
- else if (this.tapped(gestureState)) {
+ } else if (this.tapped(gestureState)) {
+ // Toggle if tapped
+ return this.toggle();
+ } else if (this.down(gestureState)) {
+ // Toggle if tapped
return this.toggle();
}
// Restore back to appropriate position otherwise
- else {
- this.restore();
- }
+ this.restore();
};
// Handle content scrolling
@@ -275,31 +278,33 @@ export default class Drawer extends Component {
};
// Check if gesture was a tap
- tapped = (gestureState) => gestureState.dx === 0 && gestureState.dy === 0;
+ tapped = gestureState => gestureState.dx === 0 && gestureState.dy === 0;
+
+ down = gestureState => gestureState.dy > 0;
// Check if pulled up
- pulledUp = (gestureState) => gestureState.dy < 0;
+ pulledUp = gestureState => gestureState.dy < 0;
// Check if pulled down
- pulledDown = (gestureState) => gestureState.dy > 0;
+ pulledDown = gestureState => gestureState.dy > 0;
// Check if pulled rapidly
- pulledFast = (gestureState) => Math.abs(gestureState.vy) > 0.75;
+ pulledFast = gestureState => Math.abs(gestureState.vy) > 0.75;
// Check if pulled far
- pulledFar = (gestureState) => Math.abs(gestureState.dy) > 50;
+ pulledFar = gestureState => Math.abs(gestureState.dy) > 50;
// Check if current position is inside allowed range
insideAllowedRange = () =>
- this._currentPosition >= this.config.position.min
- && this._currentPosition <= this.config.position.max;
+ this._currentPosition >= this.config.position.min &&
+ this._currentPosition <= this.config.position.max;
// Open up the window on full screen
open = () => {
this.setState({ open: true }, () => {
Animated.timing(this._animatedPosition, {
toValue: this.config.position.end,
- duration: 400,
+ duration: 400
}).start();
});
};
@@ -309,18 +314,21 @@ export default class Drawer extends Component {
this._scrollView.scrollTo({ y: 0 });
Animated.timing(this._animatedPosition, {
toValue: this.config.position.start,
- duration: 400,
- }).start(() => this.setState({
- open: false,
- }));
+ duration: 400
+ }).start(() => {
+ this.setState({
+ open: false
+ });
+
+ this._scrollView.scrollTo({ y: 0 });
+ });
};
// Toggle window state between opened and closed
toggle = () => {
if (!this.state.open) {
this.open();
- }
- else {
+ } else {
this.close();
}
};
@@ -329,64 +337,65 @@ export default class Drawer extends Component {
restore = () => {
if (this.state.open) {
this.open();
- }
- else {
+ } else {
this.close();
}
};
// Get header style
getHeaderStyle = () => ({
- height: Platform.OS === 'ios'
- ? this.props.headerHeight
- : this.props.headerHeight - 40, // compensate for the status bar
+ height:
+ Platform.OS === "ios"
+ ? this.props.headerHeight
+ : this.props.headerHeight - 40 // compensate for the status bar
});
// Get container style
getContainerStyle = () => ({
// Move the view below others if not open or moving
// to not block gesture handlers on other views
- zIndex: this.state.pulling || this.state.open ? 1 : -1,
+ zIndex: this.state.pulling || this.state.open ? 1 : -1
});
}
const styles = StyleSheet.create({
// Main container
container: {
- ...StyleSheet.absoluteFillObject, // fill up all screen
- alignItems: 'center', // center children
- justifyContent: 'flex-end', // align popup at the bottom
- backgroundColor: 'transparent', // transparent background
+ ...StyleSheet.absoluteFillObject, // fill up all screen
+ alignItems: "center", // center children
+ justifyContent: "flex-end", // align popup at the bottom
+ backgroundColor: "transparent", // transparent background
+ elevation: 999 // fix android dynamic zindex issue
},
// Semi-transparent background below popup
backdrop: {
- ...StyleSheet.absoluteFillObject, // fill up all screen
- alignItems: 'center', // center children
- justifyContent: 'flex-start', // align popup at the bottom
- backgroundColor: 'black',
+ ...StyleSheet.absoluteFillObject, // fill up all screen
+ alignItems: "center", // center children
+ justifyContent: "flex-start", // align popup at the bottom
+ backgroundColor: "black"
},
// Body
content: {
- backgroundColor: 'black',
- height: height,
+ backgroundColor: "black",
+ height
},
// Header
header: {
- flexDirection: 'row', // arrange children in a row
- alignItems: 'center', // center vertically
+ flexDirection: "row", // arrange children in a row
+ alignItems: "center", // center vertically
paddingTop: 20,
- paddingHorizontal: 20,
+ paddingHorizontal: 20
},
headerIcon: {
- marginRight: 10,
+ marginRight: 10
},
headerTitle: {
- flex: 1, // take up all available space
+ flex: 1 // take up all available space
},
headerText: {
- color: 'white',
- fontFamily: 'Avenir',
- fontWeight: '600',
- fontSize: 16,
- },
+ color: "white",
+ fontFamily: "Avenir",
+ fontWeight: "600",
+ fontSize: 16
+ }
});