Skip to content

Instantly share code, notes, and snippets.

@PrimeTimeTran
Last active January 13, 2019 16:03
Show Gist options
  • Save PrimeTimeTran/5e0e565c852fff17a1d702b676623293 to your computer and use it in GitHub Desktop.
Save PrimeTimeTran/5e0e565c852fff17a1d702b676623293 to your computer and use it in GitHub Desktop.
import React, { Component } from 'react'
import {
Animated,
Platform,
StyleSheet,
TouchableOpacity
} from 'react-native'
import PropTypes from 'prop-types'
import { Icon } from 'react-native-elements'
import { t } from 'locales'
import Colors, { isiPhoneXSMax } from 'style'
const NAVBAR_HEIGHT = isiPhoneXSMax() ? 110 : 64
const statusBarHeightiOS = isiPhoneXSMax() ? 60 : 20
const STATUS_BAR_HEIGHT = Platform.select({ ios: statusBarHeightiOS, android: 24 })
export class CollapsibleHeader extends Component {
static propTypes = {
rightIcon: PropTypes.func
}
static defaultProps = {
rightIcon: () => {}
}
_clampedScrollValue = 0
_offsetValue = 0
_scrollValue = 0
constructor(props) {
super(props)
const scrollAnim = new Animated.Value(0)
const offsetAnim = new Animated.Value(0)
this.state = {
scrollAnim,
offsetAnim,
clampedScroll: Animated.diffClamp(
Animated.add(
scrollAnim.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
extrapolateLeft: 'clamp'
}),
offsetAnim,
),
0,
NAVBAR_HEIGHT - STATUS_BAR_HEIGHT,
)
}
this.props.onRef(this)
}
componentWillMount() {
this.props.navigation.setParams({ scrollToTop: this.scrollToTop })
}
componentDidMount() {
const { scrollAnim, offsetAnim } = this.state
scrollAnim.addListener(({ value }) => {
const diff = value - this._scrollValue
this._scrollValue = value
this._clampedScrollValue = Math.min(
Math.max(this._clampedScrollValue + diff, 0),
NAVBAR_HEIGHT - STATUS_BAR_HEIGHT,
)
})
offsetAnim.addListener(({ value }) => {
this._offsetValue = value
})
}
componentWillUnmount() {
const { scrollAnim, offsetAnim } = this.state
scrollAnim.removeAllListeners()
offsetAnim.removeAllListeners()
}
scrollToTop = () => {
const { current: { _component } } = this.props.referencingComponent
if (_component) {
_component.scrollToPosition(null, 0)
}
}
_onScrollEndDrag = () => {
this._scrollEndTimer = setTimeout(this._onMomentumScrollEnd, 250)
}
_onMomentumScrollBegin = () => {
clearTimeout(this._scrollEndTimer)
}
_onMomentumScrollEnd = () => {
const { offsetAnim } = this.state
const toValue = this._scrollValue > NAVBAR_HEIGHT &&
this._clampedScrollValue > (NAVBAR_HEIGHT - STATUS_BAR_HEIGHT) / 2
? this._offsetValue + NAVBAR_HEIGHT
: this._offsetValue - NAVBAR_HEIGHT
Animated.timing(offsetAnim, {
toValue,
duration: 350,
useNativeDriver: true
}).start()
}
scrollAnim = () => {
const { scrollAnim } = this.state
return scrollAnim
}
render() {
const {
titleStyle,
navbarStyle,
} = styles
const {
rightIcon,
screenTitle,
navigation: {
navigate,
openDrawer
}
} = this.props
const { clampedScroll } = this.state
const navbarTranslate = clampedScroll.interpolate({
extrapolate: 'clamp',
inputRange: [0, NAVBAR_HEIGHT - STATUS_BAR_HEIGHT],
outputRange: [0, -(NAVBAR_HEIGHT - STATUS_BAR_HEIGHT)]
})
const navbarOpacity = clampedScroll.interpolate({
extrapolate: 'clamp',
outputRange: [1, 0],
inputRange: [0, NAVBAR_HEIGHT - STATUS_BAR_HEIGHT]
})
return (
<Animated.View style={[navbarStyle, { transform: [{ translateY: navbarTranslate }] }]}>
<Animated.View style={{ opacity: navbarOpacity }}>
<TouchableOpacity
onPress={openDrawer}
style={{ padding: 10 }}
>
<Icon type="material-community" name="menu" color="white" size={26} />
</TouchableOpacity>
</Animated.View>
<Animated.Text style={[titleStyle, { opacity: navbarOpacity }]}>
{screenTitle}
</Animated.Text>
<Animated.View style={{ opacity: navbarOpacity }}>
{rightIcon()}
</Animated.View>
</Animated.View>
)
}
}
const styles = StyleSheet.create({
navbarStyle: {
top: 0,
left: 0,
right: 0,
position: 'absolute',
alignItems: 'center',
flexDirection: 'row',
height: NAVBAR_HEIGHT,
borderBottomColor: '#dedede',
paddingTop: STATUS_BAR_HEIGHT,
justifyContent: 'space-between',
backgroundColor: Colors.navigationHeaderBackgroundColor
},
titleStyle: {
fontSize: 18,
color: Colors.titleColor
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment