Created
November 1, 2017 16:11
-
-
Save agibson73/1f1e5ae1d4b98468aa7947d66297f28c to your computer and use it in GitHub Desktop.
RNCollapse Mess
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Sample React Native App | |
* https://github.com/facebook/react-native | |
* @flow | |
*/ | |
import React, { Component } from 'react'; | |
import { | |
AppRegistry, | |
StyleSheet, | |
Text, | |
View, | |
Animated, | |
Dimensions, | |
TouchableWithoutFeedback, | |
ScrollView, | |
PanResponder | |
} from 'react-native'; | |
const { width, height } = Dimensions.get('window'); | |
class ScrollViewWithPan extends Component { | |
// Configure animations | |
config = { | |
// Window position | |
position: { | |
// maximum possible value - the bottom edge of the screen | |
max: height, | |
// starting value - teaserHeight higher than the bottom of the screen | |
start: height * 0.45, | |
// end value - headerHeight lower than the top of the screen | |
end: 20, | |
// minimal possible value - a bit lower the top of the screen | |
min: 20, | |
// When animated triggers these value updates | |
animates: [ | |
() => this._animatedHeight, | |
] | |
}, | |
// Window width | |
height: { | |
end: height, | |
start: height * 0.45, | |
}, | |
}; | |
// Pan responder to handle gestures | |
_panResponder = {}; | |
// Animates window height | |
_animatedHeight = new Animated.Value(this.config.height.start); | |
// Animates window position | |
_animatedPosition = new Animated.Value(this.props.isOpen | |
? this.config.position.end | |
: this.config.position.start); | |
constructor(props){ | |
super(props); | |
this.state = { | |
distance : 200, | |
pan : new Animated.ValueXY(), //Step 1 | |
shouldRespond : false, | |
pulling:false, | |
open:false, | |
scrollOffset:0, | |
targetY:(height * 0.55)- 100, | |
scrollEnabled : true, | |
active : false, | |
startdY : null, | |
}; | |
// Set current position | |
this._currentPosition = this._animatedPosition._value; | |
// Listen for this._animatedPosition changes | |
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); | |
// Initialize PanResponder to handle gestures | |
this._panResponder = PanResponder.create({ | |
onStartShouldSetPanResponder: this._grantPanResponder, | |
onStartShouldSetPanResponderCapture: this._grantPanResponder, | |
onMoveShouldSetPanResponder: this._grantPanResponder, | |
onMoveShouldSetPanResponderCapture: this._grantPanResponder, | |
onPanResponderGrant: this._handlePanResponderGrant, | |
onPanResponderMove: this._handlePanResponderMove, | |
onPanResponderTerminationRequest: (evt, gestureState) => true, | |
onPanResponderRelease: this._handlePanResponderEnd, | |
onPanResponderTerminate: this._handlePanResponderEnd, | |
onShouldBlockNativeResponder: (evt, gestureState) => false, | |
}); | |
} | |
// Handle isOpen prop changes to either open or close the window | |
componentWillReceiveProps(nextProps) { | |
// 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) { | |
this.close(); | |
} | |
} | |
render() { | |
// console.log('the animated height is',this._animatedHeight) | |
// console.log('the translation is',this._animatedPosition) | |
var reponder = this._panResponder.panHandlers | |
if(this.state.active){ | |
reponder = null | |
} | |
return ( | |
<View style = {{flex:1}}> | |
<Animated.View style = {{height:this._animatedHeight,width:width,backgroundColor:'gray'}}></Animated.View> | |
<View style = {{flex:1}}> | |
<ScrollView style = {{flex:1}} | |
horizontal = {false} | |
ref={(scrollView) => { this._scrollView = scrollView; }} | |
// Enable scrolling only when the window is open | |
scrollEnabled={this.state.scrollEnabled} | |
// Hide all scrolling indicators | |
showsHorizontalScrollIndicator={false} | |
showsVerticalScrollIndicator={false} | |
// Trigger onScroll often | |
scrollEventThrottle={16} | |
onScroll={({nativeEvent}) => { | |
}} | |
{...reponder}> | |
{this.renderScrollView()} | |
</ScrollView> | |
</View> | |
</View> | |
); | |
} | |
renderScrollView(){ | |
let views = [] | |
for (x = 0; x<30;x++){ | |
views.push(x) | |
} | |
return (views.map((prop, key) => { | |
return ( | |
<View style={{height: 100,marginBottom:20,width:width,backgroundColor:'blue'}} key={key}></View> | |
); | |
})) | |
} | |
// Either allow or deny gesture handler | |
_grantPanResponder = (evt, gestureState) => { | |
return true | |
}; | |
// Called when granted | |
_handlePanResponderGrant = (evt, gestureState) => { | |
}; | |
// Called when being pulled | |
_handlePanResponderMove = (evt, gestureState) => { | |
// console.log('the gesture is ',gestureState.moveY) | |
//console.log('the gesture is ',gestureState) | |
if (gestureState.moveY < this.state.targetY){ | |
console.log('the target Y is',this.state.targetY) | |
console.log('the current move is',gestureState.moveY) | |
if (this.state.scrollEnabled){ | |
this.setState({ | |
scrollEnabled :false, | |
}) | |
} | |
if (!this.state.startdY){ | |
console.log('setting the start value to',gestureState.dy) | |
this.state.startdY = gestureState.dy | |
} | |
console.log('the animated height',this._animatedHeight) | |
console.log('the starting value is',this.state.startdY) | |
console.log('the gesture dy is',gestureState.dy) | |
this._animatedHeight.setValue(((height * 0.55)- 100) + (gestureState.dy + (-this.state.startdY))); | |
}else{ | |
//scroll the scrollview | |
} | |
}; | |
// Called when gesture ended | |
_handlePanResponderEnd = (evt, gestureState) => { | |
this.setState({ | |
scrollEnabled :true, | |
startdY:null, | |
}) | |
}; | |
// Handle content scrolling | |
isCloseToTop(e) { | |
console.log('the native event is',e) | |
return false | |
}; | |
// Check if gesture was a tap | |
tapped = (gestureState) => gestureState.dx === 0 && gestureState.dy === 0; | |
// Check if pulled up | |
pulledUp = (gestureState) => gestureState.dy < 0; | |
// Check if pulled down | |
pulledDown = (gestureState) => gestureState.dy > 0; | |
// Check if pulled rapidly | |
pulledFast = (gestureState) => Math.abs(gestureState.vy) > 0.75; | |
// Check if pulled far | |
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; | |
// Open up the window on full screen | |
open = () => { | |
this.setState({ open: true }, () => { | |
Animated.timing(this._animatedPosition, { | |
toValue: this.config.position.end, | |
duration: 400, | |
}).start(); | |
}); | |
}; | |
// Minimize window and keep a teaser at the bottom | |
close = () => { | |
// this._scrollView.scrollTo({ y: 0 }); | |
// Animated.timing(this._animatedPosition, { | |
// toValue: this.config.position.start, | |
// duration: 400, | |
// }).start(() => this.setState({ | |
// open: false, | |
// })); | |
}; | |
// Toggle window state between opened and closed | |
toggle = () => { | |
if (!this.state.open) { | |
this.open(); | |
} | |
else { | |
this.close(); | |
} | |
}; | |
// Either open or close depending on the state | |
restore = () => { | |
if (this.state.open) { | |
this.open(); | |
} | |
else { | |
this.close(); | |
} | |
}; | |
// 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, | |
}); | |
} | |
const styles = StyleSheet.create({ | |
container: { | |
flex: 1, | |
}, | |
square: { | |
width: 50, | |
height: 50, | |
backgroundColor: 'blue', | |
}, | |
button: { | |
alignSelf: 'center', | |
paddingTop: 50, | |
}, | |
}); | |
module.exports = ScrollViewWithPan; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment