Skip to content

Commit

Permalink
takes object/array/StyleSheet styles. automatically adjusts width to …
Browse files Browse the repository at this point in the history
…container

version 1.03
  • Loading branch information
mileung committed May 26, 2017
1 parent 7ae4ac0 commit b36db8e
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 41 deletions.
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
{
"name": "top-bar-nav",
"version": "1.0.2",
"version": "1.0.3",
"private": false,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
"test": "jest",
"ios": "react-native run-ios",
"android": "react-native run-android"
},
"dependencies": {
"react": "16.0.0-alpha.6",
Expand Down
36 changes: 18 additions & 18 deletions src/Example.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ const ROUTES = {
// ideally you would have a ROUTES object with multiple React component scenes
};

const ROUTESTACK = [
{ label: 'React', title: 'Scene' }, // label is what you see in the top bar
{ label: 'Native', title: 'Scene' }, // title is just the name of the Component being rendered. See the renderScene property below
{ label: 'Is', title: 'Scene' },
{ label: 'Awesome', title: 'Scene' }
];

// const ROUTESTACK = [
// { image: require('./home.png'), title: 'Scene' },
// { image: require('./search.png'), title: 'Scene' },
// { image: require('./bell.png'), title: 'Scene' }
// { label: 'React', title: 'Scene' }, // label is what you see in the top bar
// { label: 'Native', title: 'Scene' }, // title is just the name of the Component being rendered. See the renderScene property below
// { label: 'Is', title: 'Scene' },
// { label: 'Awesome', title: 'Scene' }
// ];

const ROUTESTACK = [
{ image: require('./home.png'), title: 'Scene' },
{ image: require('./search.png'), title: 'Scene' },
{ image: require('./bell.png'), title: 'Scene' }
];

export default class Example extends React.Component {
render() {
return (
Expand All @@ -41,13 +41,13 @@ export default class Example extends React.Component {
return <Component index={i} />;
}}
// Below are optional props
// headerStyle={styles.headerStyle}
// labelStyle={styles.labelStyle}
// underlineStyle={styles.underlineStyle}
// imageStyle={styles.imageStyle}
// sidePadding={50} // Can't set sidePadding in headerStyle because it's needed to calculate the width of the tabs
// inactiveOpacity={1}
// fadeLabels={false}
headerStyle={styles.headerStyle}
labelStyle={styles.labelStyle}
underlineStyle={styles.underlineStyle}
imageStyle={styles.imageStyle}
sidePadding={40} // Can't set sidePadding in headerStyle because it's needed to calculate the width of the tabs
inactiveOpacity={1}
fadeLabels={false}
/>
</View>
);
Expand All @@ -72,7 +72,7 @@ const styles = StyleSheet.create({
tintColor: '#e6faff'
},
underlineStyle: {
height: 1.6,
height: 3.6,
backgroundColor: '#e6faff'
}
});
64 changes: 43 additions & 21 deletions src/TopBarNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ let { width } = Dimensions.get('window');

const stylePropType = React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array,
React.PropTypes.number
]);

Expand Down Expand Up @@ -61,16 +62,15 @@ export default class TopBarNav extends React.Component {
fadeLabels: true
};

componentWillMount() {
let { sidePadding, routeStack } = this.props;
let { length } = routeStack;

this.tabWidth = (width - sidePadding * 2) / length;
this.scrollX = new Animated.Value(0);

this.maxInput = (length - 1) * width;
this.maxRange = width - this.tabWidth - sidePadding * 2;
state = {
width: 1, // 1 to prevent dividing by zero later on
tabWidth: 0,
scrollX: new Animated.Value(0),
maxInput: 0,
maxRange: 0,
previousWidth: null
}

render() {
let {
labels,
Expand All @@ -86,16 +86,21 @@ export default class TopBarNav extends React.Component {
fadeLabels
} = this.props;

let { width, tabWidth, scrollX, maxInput, maxRange } = this.state;


let position = Animated.divide(this.scrollX, width);
let position = Animated.divide(scrollX, width);

let underlineX = position.interpolate({
inputRange: [0, routeStack.length - 1],
outputRange: [0, this.maxRange]
outputRange: [0, maxRange]
});

return (
<View style={{ flex: 1 }}>
<View
onLayout={this.calibrate}
style={{ flex: 1 }}
>
<View style={[headerStyle, { paddingHorizontal: sidePadding }]}>
<View
style={{
Expand Down Expand Up @@ -138,7 +143,7 @@ export default class TopBarNav extends React.Component {
overflow: 'hidden',
alignSelf: 'center'
}}>
<Animated.View style={{ marginLeft: underlineX, width: this.tabWidth }}>
<Animated.View style={{ marginLeft: underlineX, width: tabWidth }}>
<View style={underlineStyle} />
</Animated.View>
</View>
Expand All @@ -150,17 +155,34 @@ export default class TopBarNav extends React.Component {
showsHorizontalScrollIndicator={false}
scrollEventThrottle={16}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { x: this.scrollX } } }]
[{ nativeEvent: { contentOffset: { x: scrollX } } }]
)}>
{routeStack.map((route, i) => {
return (
<View key={i} style={{ width }}>
{renderScene(route, i)}
</View>
);
})}
{routeStack.map((route, i) => (
<View key={i} style={{ width }}>
{renderScene(route, i)}
</View>
))}
</ScrollView>
</View>
);
}

calibrate = ({ nativeEvent }) => {
let index = Math.ceil(this.state.scrollX._value / this.state.previousWidth);
let { width } = nativeEvent.layout;
let { sidePadding, routeStack } = this.props;
let { length } = routeStack;

let tabWidth = (width - sidePadding * 2) / length;
let maxInput = (length - 1) * width;
let maxRange = width - tabWidth - sidePadding * 2;

this.setState({
width,
tabWidth,
maxInput,
maxRange,
previousWidth: width
}, () => setTimeout(() => this.scrollView.scrollTo({ x: index * width }), 1));
}
}

0 comments on commit b36db8e

Please sign in to comment.