Skip to content

Instantly share code, notes, and snippets.

@khatv911
Created May 11, 2017 04:40
Show Gist options
  • Save khatv911/4fcf11da8fd827b55b7a0159c0eafef3 to your computer and use it in GitHub Desktop.
Save khatv911/4fcf11da8fd827b55b7a0159c0eafef3 to your computer and use it in GitHub Desktop.
Hidden SearchBar on scroll
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