Skip to content

Instantly share code, notes, and snippets.

@gabecoyne
Last active October 18, 2016 12:14
Show Gist options
  • Save gabecoyne/3b9ffa89b07ac4f42dc7 to your computer and use it in GitHub Desktop.
Save gabecoyne/3b9ffa89b07ac4f42dc7 to your computer and use it in GitHub Desktop.
React Native Android ViewPager
'use-strict'
var React = require('react-native');
var {
Dimensions
} = React;
var DimensionsHelper = {
init : function() {
this.SCREEN_WIDTH = Dimensions.get("window").width;
this.SCREEN_HEIGHT = Dimensions.get("window").height;
}
}
DimensionsHelper.init();
module.exports = DimensionsHelper
'use strict';
var React = require('react-native');
var {
View,
ViewPagerAndroid,
Text
} = React;
var ViewPagerTabs = require("./ViewPagerTabs");
var ViewPagerDots = require("./ViewPagerDots");
var DimensionsHelper = require("./DimensionsHelper");
var ViewPager = React.createClass({
componentDidMount: function(){
console.log("ViewPager componentDidMount");
},
getDefaultProps: function(){
},
getInitialState: function(){
return {
activeTab:0
}
},
goToPage: function(page){
this.setState({activeTab: page});
},
onPageScroll: function(e){
this.tabs.onPageScroll(e);
},
onPageSelected: function(e){
this.tabs.onPageSelected(e);
},
renderTabBar() {
if (this.props.bar === 'tabs') {
return <ViewPagerTabs children={this.props.children} viewPager={() => {return this.viewPager}} ref={(comp) => {this.tabs = comp}} />;;
} else {
return <ViewPagerDots children={this.props.children} viewPager={() => {return this.viewPager}} ref={(comp) => {this.tabs = comp}} />;;
}
},
render() {
return (
<View>
{this.props.position == 'top' ? this.renderTabBar() : null}
<ViewPagerAndroid ref={(comp) => {this.viewPager = comp}}
onPageScroll={this.onPageScroll}
onPageSelected={this.onPageSelected}
style={{
flexDirection:'row',
backgroundColor:'#ccc',
height: this.props.height || 300,
width: this.props.width || DimensionsHelper.SCREEN_WIDTH
}}
>
{this.props.children}
</ViewPagerAndroid>
{this.props.position == 'bottom' ? this.renderTabBar() : null}
</View>
);
}
});
module.exports = ViewPager;
'use strict';
var React = require('react-native');
var {
View,
Text,
ViewPagerAndroid,
StyleSheet,
TouchableOpacity
} = React;
var DimensionsHelper = require("./DimensionsHelper");
var ViewPagerDots = React.createClass({
getDefaultProps: function(){
},
getInitialState: function(){
return { activeTab:0 }
},
// called from ViewPager
onPageScroll: function(e){
this.setState({random:1})
},
// called from ViewPager
onPageSelected: function(e){
this.setState({activeTab: e.nativeEvent.position});
},
// goto(2)
goToPage: function(page){
console.log("goToPage", page);
this.props.viewPager().setPage(page);
this.setState({activeTab: page});
},
renderTab(child, page){
var isTabActive = this.state.activeTab === page;
return (
<TouchableOpacity onPress={() => this.goToPage(page)}>
<View style={[styles.dot, (isTabActive ? styles.active : styles.inactive)]} />
</TouchableOpacity>
)
},
render() {
return (
<View style={styles.dots} {...this.props}>
{this.props.children.map((child, i) => this.renderTab(child, i))}
</View>
);
}
});
var styles = StyleSheet.create({
dots: {
height:40,
flex:1,
flexDirection: 'row',
alignItems:'center',
justifyContent: 'center'
},
dot: {
width: 10,
height: 10,
marginHorizontal: 3,
borderRadius: 5,
borderWidth: 1,
borderColor: "#ccc",
backgroundColor: "#fff"
},
active: {
backgroundColor: "#ccc"
},
intactive: {
backgroundColor: "#fff"
}
});
module.exports = ViewPagerDots;
'use strict';
var React = require('react-native');
var {
View,
Text,
ViewPagerAndroid,
StyleSheet,
TouchableOpacity
} = React;
var DimensionsHelper = require("./DimensionsHelper");
var ViewPagerTabs = React.createClass({
getDefaultProps: function(){
},
getInitialState: function(){
return {
activeTab:0,
left: 0
}
},
moveActiveLine:function(e){
console.log("ViewPagerTabs.moveActiveLine", e.nativeEvent);
var width = DimensionsHelper.SCREEN_WIDTH
var tabWidth = width / this.props.children.length;
var left = (tabWidth * (e.nativeEvent.offset || 0)) + (tabWidth * e.nativeEvent.position);
if(!e.nativeEvent.position || left) this.setState({left: left});
},
// called from ViewPager
onPageScroll: function(e){
this.moveActiveLine(e);
},
// called from ViewPager
onPageSelected: function(e){
// this.moveActiveLine(e);
this.setState({activeTab: e.nativeEvent.position});
},
// goto(2)
goToPage: function(page){
console.log("goToPage", page);
this.props.viewPager().setPage(page);
this.setState({activeTab: page});
},
renderTab(child, page){
var isTabActive = this.state.activeTab === page;
var textStyle = {
color: isTabActive ? '#666' : '#999',
fontWeight: isTabActive ? 'bold' : 'normal'
}
return (
<TouchableOpacity
style={[
styles.tab,
{width: DimensionsHelper.SCREEN_WIDTH/this.props.children.length}]}
onPress={() => this.goToPage(page)}>
<View>
<Text style={textStyle}>{child.props.tabLabel}</Text>
</View>
</TouchableOpacity>
)
},
render() {
return (
<View style={styles.tabs} {...this.props}>
{this.props.children.map((child, i) => this.renderTab(child, i))}
<View
ref={(comp) => {this.activeLine = comp}}
style={[styles.activeLine, {left: this.state.left, width: DimensionsHelper.SCREEN_WIDTH/this.props.children.length}]} />
</View>
);
}
});
var styles = StyleSheet.create({
tabs:{
flex: 1,
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: '#eee'
},
tab:{
height: 45,
paddingBottom: 5,
justifyContent: 'center',
alignItems: 'center'
},
activeLine:{
height: 4,
backgroundColor: '#999',
position:'absolute',
top: 42,
left: 0
}
})
module.exports = ViewPagerTabs;
@theodoregold
Copy link

Great gist, but it seems to me that passing children with content to tab/dot navigation might cause poor performance. For example, if there is a long list in each tab.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment