Created
May 11, 2017 04:40
-
-
Save khatv911/4fcf11da8fd827b55b7a0159c0eafef3 to your computer and use it in GitHub Desktop.
Hidden SearchBar on scroll
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
import React, { Component } from 'react'; | |
import { SectionList, StyleSheet, Text, View, ScrollView, Animated } from 'react-native'; | |
import { SearchBar } from 'react-native-elements'; | |
import { Navigation } from 'react-native-navigation'; | |
import LCE from '../../../../global/LCE'; | |
import RoomRowActionButtonList from './RoomRowActionButtonList'; | |
import RoomCell from './RoomCell'; | |
import { CHECK_OUT_TYPE, CHECK_IN_TYPE, STAY_OVER, CHECKED_OUT_TYPE, PROFILE_ACTION, EDIT_ACTION, DATES_ACTION, CASHIER_ACTION } from '../../../../global/constants'; | |
import SectionHeader from './SectionHeader'; | |
const {SeparatorComponent} = require('../../../../global/components/sectionComponent.js'); | |
import { iconsMap } from '../../../../global/AppIcon'; | |
import { LOCALIZATION_STRINGS } from '../../../../global/Localization'; | |
import { fetchReservation } from '../duck/actions' | |
const damping = 0.4; | |
const tension = 300; | |
const SEARCHBAR_HEIGHT = 50; | |
const AnimatedListView = Animated.createAnimatedComponent(ScrollView); | |
const AnimatedSearchBar = Animated.createAnimatedComponent(SearchBar); | |
export default class Home extends Component { | |
constructor(props) { | |
super(props); | |
// if you want to listen on navigator events, set this up | |
this | |
.props | |
.navigator | |
.setOnNavigatorEvent(this.onNavigatorEvent.bind(this)); | |
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, | |
SEARCHBAR_HEIGHT, | |
) | |
}; | |
} | |
_clampedScrollValue = 0; | |
_offsetValue = 0; | |
_scrollValue = 0; | |
componentWillUnmount() { | |
this.state.scrollAnim.removeAllListeners(); | |
this.state.offsetAnim.removeAllListeners(); | |
} | |
componentDidMount() { | |
this.state.scrollAnim.addListener(({value}) => { | |
const diff = value - this._scrollValue; | |
this._scrollValue = value; | |
this._clampedScrollValue = Math.min( | |
Math.max(this._clampedScrollValue + diff, 0), | |
SEARCHBAR_HEIGHT, | |
); | |
}); | |
this.state.offsetAnim.addListener(({value}) => { | |
this._offsetValue = value; | |
}); | |
const {dispatch} = this.props; | |
this.props.navigator.setButtons({ | |
rightButtons: [ | |
{ | |
icon: iconsMap['ios-add'], // for icon button, provide the local image asset name | |
id: 'add', // id for this button, given in onNavigatorEvent(event) to help understand which button was clicked | |
} | |
] | |
}) | |
this.props.navigator.setStyle({ | |
// iOS only | |
disabledBackGesture: false, // default: false. Disable the back gesture (swipe gesture) in order to pop the top screen. | |
// Android only | |
navigationBarColor: '#000000', // change the background color of the bottom native navigation bar. | |
navBarTitleTextCentered: true, // default: false. centers the title. | |
topBarElevationShadowEnabled: false, // default: true. Disables TopBar elevation shadow on Lolipop and above | |
statusBarColor: '#000000', // change the color of the status bar. | |
collapsingToolBarCollapsedColor: '#0f2362', // Collapsing Toolbar scrim color. | |
}); | |
dispatch(fetchReservation()); | |
// setTimeout(() => { dispatch(startHome()); }, 500); setTimeout(() => { | |
// dispatch(errorHome()); }, 3000); setTimeout(() => { dispatch(fakeSuccess()); | |
// }, 5000); | |
} | |
onNavigatorEvent(event) { // this is the onPress handler for the two buttons together | |
if (event.type == 'NavBarButtonPress') { // this is the event type for button presses | |
if (event.id == 'edit') { // this is the same id field from the static navigatorButtons definition | |
alert('Edit button pressed'); | |
} | |
if (event.id == 'add') { | |
// this would go inside the Component implementation of one of your screens, | |
// like FirstTabScreen.js | |
this | |
.props | |
.navigator | |
.push({ | |
screen: 'mcosmo.NewReservation', | |
title: LOCALIZATION_STRINGS.newReservation, | |
backButtonTitle: '' | |
}); | |
} | |
} | |
} | |
_onScrollEndDrag = () => { | |
this._scrollEndTimer = setTimeout(this._onMomentumScrollEnd, 250); | |
}; | |
_onMomentumScrollBegin = () => { | |
clearTimeout(this._scrollEndTimer); | |
}; | |
_onMomentumScrollEnd = () => { | |
const toValue = this._scrollValue > SEARCHBAR_HEIGHT && | |
this._clampedScrollValue > (SEARCHBAR_HEIGHT) / 2 | |
? this._offsetValue + SEARCHBAR_HEIGHT | |
: this._offsetValue - SEARCHBAR_HEIGHT; | |
Animated.timing(this.state.offsetAnim, { | |
toValue, | |
duration: 350, | |
useNativeDriver: true, | |
}).start(); | |
}; | |
retry = () => { | |
alert("let's retry"); | |
} | |
_renderItemComponent = ({item}) => ( | |
<RoomRowActionButtonList damping={ damping } tension={ tension } roomNo={ item.roomNo } handleClick={ (...args) => this.actionButtonClick(...args) }> | |
<RoomCell item={ item } cellSelected={ (...args) => this.cellSelected(...args) } /> | |
</RoomRowActionButtonList> | |
); | |
_moveToScreen(screen) { | |
this | |
.props | |
.navigator | |
.push(screen); | |
} | |
actionButtonClick = (type, roomNo) => { | |
let screen = {}; | |
switch (type) { | |
case PROFILE_ACTION: | |
screen = { | |
screen: 'mcosmo.ProfileReservation', | |
title: 'Profile' | |
} | |
break; | |
case EDIT_ACTION: | |
screen = { | |
screen: 'mcosmo.EditReservation', | |
title: 'Edit' | |
} | |
break; | |
case DATES_ACTION: | |
screen = { | |
screen: 'mcosmo.DatesReservation', | |
title: 'Dates' | |
} | |
break; | |
case CASHIER_ACTION: | |
screen = { | |
screen: 'mcosmo.CashierReservation', | |
title: 'Cashier' | |
} | |
break; | |
default: | |
screen = { | |
screen: 'mcosmo.EditReservation', | |
title: 'Edit' | |
} | |
break; | |
} | |
this._moveToScreen(screen); | |
} | |
cellSelected = (selectedRoom) => { | |
let screen = {}; | |
switch (selectedRoom.type) { | |
case CHECK_OUT_TYPE: | |
screen = { | |
screen: 'mcosmo.CheckOut', | |
title: 'Check Out' | |
} | |
break; | |
case CHECK_IN_TYPE: | |
screen = { | |
screen: 'mcosmo.CheckIn', | |
title: 'Check In' | |
} | |
break; | |
case STAY_OVER: | |
screen = { | |
screen: 'mcosmo.StayOver', | |
title: 'Stay Over' | |
} | |
break; | |
case CHECKED_OUT_TYPE: | |
screen = { | |
screen: 'mcosmo.CheckedOut', | |
title: 'Checked Out' | |
} | |
break; | |
default: | |
screen = { | |
screen: 'mcosmo.EditReservation', | |
title: 'Edit' | |
} | |
break; | |
} | |
this._moveToScreen(screen); | |
} | |
render() { | |
const {clampedScroll} = this.state; | |
const navbarTranslate = clampedScroll.interpolate({ | |
inputRange: [0, SEARCHBAR_HEIGHT], | |
outputRange: [0, -(SEARCHBAR_HEIGHT)], | |
extrapolate: 'clamp', | |
}); | |
const navbarOpacity = clampedScroll.interpolate({ | |
inputRange: [0, SEARCHBAR_HEIGHT], | |
outputRange: [1, 0], | |
extrapolate: 'clamp', | |
}); | |
const {isLoading, hasError, reservation} = this.props; | |
const error = { | |
message: 'have error' | |
}; | |
const action = { | |
text: 'RETRY', | |
actionFn: this.retry | |
}; | |
const SectionList = reservation.map((data, i) => { | |
const ItemList = data.data.map((item, i) => { | |
return ( | |
<RoomRowActionButtonList damping={ damping } tension={ tension } roomNo={ item.roomNo } handleClick={ (...args) => this.actionButtonClick(...args) } key={ i }> | |
<RoomCell item={ item } roomNo={ item.roomNo } roomType='STDB' guestName='Taylor Malloran' guestType='Guest' cellSelected={ (...args) => this.cellSelected(...args) } key={ i } | |
/> | |
</RoomRowActionButtonList> | |
) | |
}); | |
return ( | |
<SectionHeader title={ data.title } items={ data.data } key={ i }> | |
{ ItemList } | |
</SectionHeader> | |
) | |
}) | |
return ( | |
<LCE isLoading={ isLoading } hasError={ hasError } error={ error } actionOnError={ action }> | |
<Animated.View style={ [styles.navbar, { transform: [{ translateY: navbarTranslate }] }] }> | |
<SearchBar containerStyle={ { backgroundColor: '#CDCED2', borderTopColor: '#CDCED2', borderBottomColor: '#CDCED2' } } inputStyle={ { backgroundColor: 'white' } } placeholder='Search' /> | |
</Animated.View> | |
<AnimatedListView bounces={ false } style={ [styles.navbar, { transform: [{ translateY: navbarTranslate }] }] } scrollEventThrottle={ 1 } onMomentumScrollBegin={ this._onMomentumScrollBegin } onMomentumScrollEnd={ this._onMomentumScrollEnd } | |
onScrollEndDrag={ this._onScrollEndDrag } onScroll={ Animated.event( | |
[{ | |
nativeEvent: { | |
contentOffset: { | |
y: this.state.scrollAnim | |
} | |
} | |
}], | |
{ | |
useNativeDriver: true | |
}, | |
) } contentContainerStyle={ { paddingBottom: 10 } }> | |
{ SectionList } | |
</AnimatedListView> | |
</LCE> | |
); | |
} | |
} | |
const styles = StyleSheet.create({}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment