Skip to content

Instantly share code, notes, and snippets.

@somangshu
Created February 26, 2019 08:01
Show Gist options
  • Save somangshu/9cbd75b1dedf5c39fc00362eb8f5169a to your computer and use it in GitHub Desktop.
Save somangshu/9cbd75b1dedf5c39fc00362eb8f5169a to your computer and use it in GitHub Desktop.
React native animated scrollview
import React, { Component } from 'react';
import {
Animated,
Platform,
StatusBar,
StyleSheet,
Text,
View,
RefreshControl,
} from 'react-native';
import MealDetailView from './MealDetailView';
import { RkButton } from 'react-native-ui-kitten';
import { SCREEN_WIDTH } from '../assets/theme';
import axios from 'axios';
import { Loading } from '../components/Loading';
const HEADER_MAX_HEIGHT = 250;
const HEADER_MIN_HEIGHT = Platform.OS === 'ios' ? 60 : 73;
const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT;
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
scrollY: new Animated.Value(
// iOS has negative initial scroll value because content inset...
Platform.OS === 'ios' ? -HEADER_MAX_HEIGHT : 0,
),
refreshing: false,
details: {},
isLoading: true
};
}
componentDidMount() {
axios.get('/catalog/' + this.props.navigation.state.params.id).then((response) => {
this.setState({
details: response.data,
isLoading: false
})
}).catch((error) => {
console.log('geg', error)
});
}
_renderScrollViewContent() {
return (
<View style={styles.scrollViewContent}>
<MealDetailView screenProps={{ details: this.state.details, navigation: this.props.navigation }} />
</View>
);
}
render() {
// Because of content inset the scroll value will be negative on iOS so bring
// it back to 0.
const scrollY = Animated.add(
this.state.scrollY,
Platform.OS === 'ios' ? HEADER_MAX_HEIGHT : 0,
);
const headerTranslate = scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE],
outputRange: [0, -HEADER_SCROLL_DISTANCE],
extrapolate: 'clamp',
});
const imageOpacity = scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE],
outputRange: [0.6, 0.5, 0.2],
extrapolate: 'clamp',
});
const imageTranslate = scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE],
outputRange: [0, 100],
extrapolate: 'clamp',
});
const titleScale = scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE],
outputRange: [1, 1, 0.9],
extrapolate: 'clamp',
});
const titleTranslate = scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE],
outputRange: [0, 0, -22],
extrapolate: 'clamp',
});
if (this.state.isLoading) {
return <Loading size={26} />
} else {
return (
<View style={styles.fill}>
<StatusBar
translucent
barStyle="light-content"
backgroundColor="#fff"
/>
<Animated.ScrollView
style={styles.fill}
scrollEventThrottle={1}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }],
{ useNativeDriver: true },
)}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={() => {
this.setState({ refreshing: true });
setTimeout(() => this.setState({ refreshing: false }), 1000);
}}
// Android offset for RefreshControl
progressViewOffset={HEADER_MAX_HEIGHT}
/>
}
// iOS offset for RefreshControl
contentInset={{
top: HEADER_MAX_HEIGHT,
}}
contentOffset={{
y: -HEADER_MAX_HEIGHT,
}}
>
{this._renderScrollViewContent()}
</Animated.ScrollView>
<Animated.View
pointerEvents="none"
style={[
styles.header,
{ transform: [{ translateY: headerTranslate }] },
]}
>
<Animated.Image
style={[
styles.backgroundImage,
{
opacity: imageOpacity,
transform: [{ translateY: imageTranslate }],
},
]}
source={require('../images/rotee_small.png')}
/>
</Animated.View>
<Animated.View
style={[
styles.bar,
{
transform: [
{ scale: titleScale },
{ translateY: titleTranslate },
],
},
]}
>
<Text style={styles.title}>{this.state.details.dish_name}</Text>
</Animated.View>
<RkButton style={styles.addButton}>Add To Cart</RkButton>
</View>
);
}
}
}
const styles = StyleSheet.create({
fill: {
flex: 1,
},
content: {
flex: 1,
},
header: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
backgroundColor: '#000',
overflow: 'hidden',
height: HEADER_MAX_HEIGHT,
},
backgroundImage: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
width: null,
opacity: 0.2,
height: HEADER_MAX_HEIGHT,
resizeMode: 'cover',
},
bar: {
backgroundColor: 'transparent',
marginTop: Platform.OS === 'ios' ? 28 : 38,
height: 32,
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
top: 0,
left: 0,
right: 0,
},
title: {
color: 'white',
fontSize: 22,
},
scrollViewContent: {
// iOS uses content inset, which acts like padding.
paddingTop: Platform.OS !== 'ios' ? HEADER_MAX_HEIGHT : 0,
},
addButton: {
backgroundColor: '#a1448a',
position: 'absolute',
bottom: 0,
height: 40,
width: SCREEN_WIDTH,
borderRadius: 0,
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment