From 4c4fdd49b7efdaa476e8807e6386c7761980c2c8 Mon Sep 17 00:00:00 2001 From: fattahmuhyiddeen Date: Wed, 4 Apr 2018 07:06:06 +0800 Subject: [PATCH 1/2] Fix z index issue on android and fix scrollview bug Fix z index issue on android and fix scrollview bug that does not completely go to top after drawer closed --- src/Drawer.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Drawer.js b/src/Drawer.js index 20f5e04..6142084 100644 --- a/src/Drawer.js +++ b/src/Drawer.js @@ -310,9 +310,13 @@ export default class Drawer extends Component { Animated.timing(this._animatedPosition, { toValue: this.config.position.start, duration: 400, - }).start(() => this.setState({ - open: false, - })); + }).start(() => { + this.setState({ + open: false, + }); + + this._scrollView.scrollTo({ y: 0 }); //set scrollview to top after drawer completely closed + }); }; // Toggle window state between opened and closed @@ -357,6 +361,7 @@ const styles = StyleSheet.create({ 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: { From 56d47085a2b4b36450cf882988199656417d109a Mon Sep 17 00:00:00 2001 From: fattahmuhyiddeen Date: Wed, 4 Apr 2018 17:10:45 +0800 Subject: [PATCH 2/2] Update Drawer.js --- src/Drawer.js | 206 +++++++++++++++++++++++++------------------------- 1 file changed, 105 insertions(+), 101 deletions(-) diff --git a/src/Drawer.js b/src/Drawer.js index 6142084..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,13 +314,13 @@ export default class Drawer extends Component { this._scrollView.scrollTo({ y: 0 }); Animated.timing(this._animatedPosition, { toValue: this.config.position.start, - duration: 400, + duration: 400 }).start(() => { this.setState({ - open: false, + open: false }); - this._scrollView.scrollTo({ y: 0 }); //set scrollview to top after drawer completely closed + this._scrollView.scrollTo({ y: 0 }); }); }; @@ -323,8 +328,7 @@ export default class Drawer extends Component { toggle = () => { if (!this.state.open) { this.open(); - } - else { + } else { this.close(); } }; @@ -333,65 +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 - elevation: 999, // fix android dynamic zindex issue + ...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 + } });