Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
RNCollapse Mess
/**
* 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