Skip to content

Commit

Permalink
Merge pull request #743 from joenoon/jn-wip
Browse files Browse the repository at this point in the history
WIP old tab bar
  • Loading branch information
aksonov committed May 30, 2016
2 parents 7e6a02c + 4e58eba commit 156edac
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 66 deletions.
49 changes: 42 additions & 7 deletions Example/Example.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Home from './components/Home'
import TabView from './components/TabView'
import EchoView from './components/EchoView'
import NavigationDrawer from './components/NavigationDrawer'
import Button from "react-native-button";

class TabIcon extends React.Component {
render(){
Expand Down Expand Up @@ -47,25 +48,59 @@ const reducerCreate = params=>{
};

// define this based on the styles/dimensions you use
const getSceneStyle = function (props) {
return {
const getSceneStyle = function (/* NavigationSceneRendererProps */ props, computedProps) {
const style = {
flex: 1,
marginTop: props.hideNavBar ? 0 : 64,
marginBottom: props.hideTabBar ? 0 : 49.5,
backgroundColor: '#fff',
shadowColor: null,
shadowOffset: null,
shadowOpacity: null,
shadowRadius: null,
};
}
if (computedProps.isActive) {
style.marginTop = computedProps.hideNavBar ? 0 : 64;
style.marginBottom = computedProps.hideTabBar ? 0 : 50;
}
return style;
};

let currentSwitchPage = 'text1';

const SwitcherPage = function (props) {
return (
<View>
<Text style={{marginTop:100,textAlign:'center'}}>current page: {props.text}</Text>
<Button
onPress={() => {
currentSwitchPage = currentSwitchPage === 'text1' ? 'text2' : 'text1';
Actions.refresh({key: 'switcher'});
}}
>
Switch!
</Button>
<Button
onPress={() => {
Actions.launch({type:'reset'});
}}
>
Exit
</Button>
</View>
);
};

export default class Example extends React.Component {
render() {
return <Router createReducer={reducerCreate} getSceneStyle={getSceneStyle}>
<Scene key="modal" component={Modal} >
<Scene key="root" hideNavBar={true} hideTabBar={true}>
<Scene key="echo" clone component={EchoView} />
<Scene key="root" hideNavBar hideTabBar>
<Scene key="echo" clone component={EchoView} getTitle={(navState) => navState.key} />
<Scene key="switcher" component={Switch} selector={(props) => {
return 'text1';
}}>
<Scene key="text1" text="text1" component={(props) => <SwitcherPage {...props} text={currentSwitchPage} />} />
<Scene key="text2" text="text2" component={(props) => <SwitcherPage {...props} text={currentSwitchPage} />} />
</Scene>
<Scene key="register" component={Register} title="Register"/>
<Scene key="register2" component={Register} title="Register2" duration={1}/>
<Scene key="home" component={Home} title="Replace" type="replace"/>
Expand Down
3 changes: 3 additions & 0 deletions Example/components/Launch.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const styles = StyleSheet.create({
justifyContent: "center",
alignItems: "center",
backgroundColor: "transparent",
borderWidth: 2,
borderColor: 'red',
}
});

Expand All @@ -22,6 +24,7 @@ class Launch extends React.Component {
<Button onPress={Actions.register2}>Go to Register page without animation</Button>
<Button onPress={()=>Actions.error("Error message")}>Popup error</Button>
<Button onPress={Actions.tabbar}>Go to TabBar page</Button>
<Button onPress={Actions.switcher}>Go to switcher page</Button>
<Button onPress={Actions.pop}>back</Button>
</View>
);
Expand Down
2 changes: 1 addition & 1 deletion Example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"dependencies": {
"react": "15.0.2",
"react-native": "^0.26.0",
"react-native": "0.26.x",
"react-native-button": "github:ide/react-native-button",
"react-native-drawer": "^2.2.2",
"react-native-modalbox": "^1.3.3",
Expand Down
6 changes: 3 additions & 3 deletions docs/API_CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,19 @@
| Property | Type | Default | Description |
|-----------|--------|---------|--------------------------------------------|
| sceneStyle | [`View style`](https://facebook.github.io/react-native/docs/view.html#style) | { flex: 1 } | optional style override for the Scene's component |
| getSceneStyle | `function` | optional | Optionally override the styles for NavigationCard's Animated.View rendering the scene. |
| getSceneStyle | `function` | optional | Optionally override the styles for NavigationCard's Animated.View rendering the scene. Receives first argument of `NavigationSceneRendererProps` and second argument of `{hideNavBar,hideTabBar,isActive}` (see Example app). |

### Tabs
| Property | Type | Default | Description |
|-----------|--------|---------|--------------------------------------------|
| tabs| `bool` | false | Defines 'TabBar' scene container, so child scenes will be displayed as 'tabs'. If no `component` is defined, built-in `TabBar` is used as renderer. All child scenes are wrapped into own navbar.
| tabBarStyle | [`View style`](https://facebook.github.io/react-native/docs/view.html#style) | | optional style override for the Tabs component |
| hideTabBar | `bool` | false | hides tab bar for this scene (if built-in TabBar component is used as parent renderer)|
| hideTabBar | `bool` | false | hides tab bar for this scene and any following scenes until explicitly reversed (if built-in TabBar component is used as parent renderer)|

### Navigation Bar
| Property | Type | Default | Description |
|-----------|--------|---------|--------------------------------------------|
| hideNavBar | `bool` | false | hides the navigation bar for this scene |
| hideNavBar | `bool` | false | hides the navigation bar for this scene and any following scenes until explicitly reversed |
| navigationBarStyle | [`View style`](https://facebook.github.io/react-native/docs/view.html#style) | | optional style override for the navigation bar |
| navBar | `React.Component` | | optional custom NavBar for the scene. Check built-in NavBar of the component for reference |
| drawerImage | [`Image source`](https://facebook.github.io/react-native/docs/image.html#source) | `'./menu_burger.png'` | Simple way to override the drawerImage in the navBar |
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
}
],
"dependencies": {
"react-native-tab-navigator": "joenoon/react-native-tab-navigator#rnrf-lock"
"react-native-tabs": "1.0.7",
"react-static-container": "1.0.1"
},
"devDependencies": {
"babel-cli": "^6.6.5",
Expand All @@ -57,10 +58,10 @@
"expect": "^1.14.0",
"mocha": "^2.4.5",
"mocha-junit-reporter": "^1.11.1",
"react": "^15.0.2",
"react-addons-test-utils": "^15.0.2",
"react-dom": "^15.0.2",
"react-native": "^0.26.0",
"react": "15.0.2",
"react-addons-test-utils": "15.0.2",
"react-dom": "15.0.2",
"react-native": "0.26.x",
"react-native-mock": "0.2.0",
"sinon": "^1.17.3"
}
Expand Down
30 changes: 24 additions & 6 deletions src/DefaultRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,21 @@ export default class DefaultRenderer extends Component {
const { key, direction, getSceneStyle } = props.scene.navigationState;
let { panHandlers, animationStyle } = props.scene.navigationState;

// Since we always need to pass a style for the direction, we can avoid #526
let style;
if (getSceneStyle) {
const hideNavBar = deepestExplicitValueForKey(props.navigationState, 'hideNavBar');
const hideTabBar = deepestExplicitValueForKey(props.navigationState, 'hideTabBar');
style = getSceneStyle({ ...props, hideNavBar, hideTabBar });
const state = props.navigationState;
const child = state.children[state.index];
let selected = state.children[state.index];
while (selected.hasOwnProperty('children')) {
selected = selected.children[selected.index];
}
const isActive = child === selected;
const computedProps = { isActive };
if (isActive) {
computedProps.hideNavBar = deepestExplicitValueForKey(props.navigationState, 'hideNavBar');
computedProps.hideTabBar = deepestExplicitValueForKey(props.navigationState, 'hideTabBar');
}

const style = getSceneStyle ? getSceneStyle(props, computedProps) : null;

const isVertical = direction === 'vertical';

if (typeof(animationStyle) === 'undefined') {
Expand Down Expand Up @@ -139,11 +146,20 @@ export default class DefaultRenderer extends Component {
selected = selected.children[selected.index];
}

if (child !== selected) {
// console.log(`SKIPPING renderHeader because ${child.key} !== ${selected.key}`);
return null;
}


const hideNavBar = deepestExplicitValueForKey(state, 'hideNavBar');
if (hideNavBar) {
// console.log(`SKIPPING renderHeader because ${child.key} hideNavBar === true`);
return null;
}

// console.log(`renderHeader for ${child.key}`);

if (selected.component && selected.component.renderNavigationBar) {
return selected.component.renderNavigationBar({ ...props, ...selected });
}
Expand Down Expand Up @@ -230,6 +246,8 @@ export default class DefaultRenderer extends Component {
}
}

// console.log(`NavigationAnimatedView for ${navigationState.key}`);

return (
<NavigationAnimatedView
navigationState={navigationState}
Expand Down
82 changes: 38 additions & 44 deletions src/TabBar.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { Component, PropTypes } from 'react';
import { View } from 'react-native';
import Tabs from 'react-native-tabs';
import DefaultRenderer from './DefaultRenderer';
import Actions from './Actions';
import TabNavigator from 'react-native-tab-navigator';
import TabbedView from './TabbedView';
import { deepestExplicitValueForKey } from './Util';

class TabBar extends Component {
Expand All @@ -11,65 +12,58 @@ class TabBar extends Component {
navigationState: PropTypes.object,
tabIcon: PropTypes.any,
onNavigate: PropTypes.func,
tabBarStyle: View.propTypes.style,
tabBarShadowStyle: View.propTypes.style,
tabSceneStyle: View.propTypes.style,
};

constructor(props, context) {
super(props, context);
this.renderScene = this.renderScene.bind(this);
}

onSelect(el) {
if (!Actions[el.sceneKey]) {
if (!Actions[el.props.name]) {
throw new Error(
`No action is defined for sceneKey=${el.sceneKey} ` +
`No action is defined for name=${el.props.name} ` +
`actions: ${JSON.stringify(Object.keys(Actions))}`);
}
Actions[el.sceneKey]();
Actions[el.props.name]();
}

renderScene(navigationState) {
return (
<DefaultRenderer
key={navigationState.key}
onNavigate={this.props.onNavigate}
navigationState={navigationState}
/>
);
}

render() {
const state = this.props.navigationState;
const selected = state.children[state.index];
const hideTabBar = deepestExplicitValueForKey(state, 'hideTabBar');

const tabBarStyle = {};

if (hideTabBar) {
tabBarStyle.opacity = 0;
tabBarStyle.height = 0;
}
const hideTabBar = deepestExplicitValueForKey(state, 'hideTabBar');

return (
<View
style={{ flex: 1 }}
>
<TabNavigator
tabBarStyle={[this.props.tabBarStyle, tabBarStyle]}
tabBarShadowStyle={this.props.tabBarShadowStyle}
sceneStyle={[{ paddingBottom: 0 }, this.props.tabSceneStyle]}
>
{state.children.map(el => {
const isSelected = el.sceneKey === selected.sceneKey;
const Icon = el.icon || this.props.tabIcon;
return (
<TabNavigator.Item
key={el.key}
selected={isSelected}
title={el.tabTitle}
renderIcon={() => <Icon {...this.props} {...el} />}
renderSelectedIcon={() => <Icon {...this.props} {...el} selected />}
onPress={() => this.onSelect(el)}
tabStyle={el.tabStyle}
titleStyle={el.tabTitleStyle}
selectedTitleStyle={el.tabSelectedTitleStyle}
>
<DefaultRenderer
key={el.key}
onNavigate={this.props.onNavigate}
navigationState={el}
/>
</TabNavigator.Item>
);
})}
</TabNavigator>
<TabbedView
navigationState={this.props.navigationState}
style={{ flex: 1 }}
renderScene={this.renderScene}
/>
{!hideTabBar && state.children.filter(el => el.icon).length > 0 &&
<Tabs
style={[{ backgroundColor: 'white' }, state.tabBarStyle]}
onSelect={this.onSelect} {...state}
selected={state.children[state.index].sceneKey}
>
{state.children.filter(el => el.icon || this.props.tabIcon).map(el => {
const Icon = el.icon || this.props.tabIcon;
return <Icon {...this.props} {...el} />;
})}
</Tabs>
}
</View>
);
}
Expand Down
68 changes: 68 additions & 0 deletions src/TabbedView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React, { Component, PropTypes } from 'react';
import { View, StyleSheet } from 'react-native';
import StaticContainer from 'react-static-container';

const styles = StyleSheet.create({
scene: {
bottom: 0,
left: 0,
position: 'absolute',
right: 0,
top: 0,
},
});

class TabbedView extends Component {

static propTypes = {
navigationState: PropTypes.object.isRequired,
renderScene: PropTypes.func.isRequired,
style: View.propTypes.style,
};

constructor(props, context) {
super(props, context);
this.renderedSceneKeys = {};
this.renderScene = this.renderScene.bind(this);
}

renderScene(navigationState, index) {
const isSelected = index === this.props.navigationState.index;
return (
<View
key={navigationState.key}
pointerEvents={isSelected ? 'auto' : 'none'}
removeClippedSubviews={!isSelected}
style={[
styles.scene,
{ opacity: isSelected ? 1 : 0 },
]}
>
<StaticContainer shouldUpdate={isSelected}>
{this.props.renderScene(navigationState, index)}
</StaticContainer>
</View>
);
}

render() {
const scenes = [];
const { index, children } = this.props.navigationState;
children.forEach((item, i) => {
const key = item.key;
if (i !== index && !this.renderedSceneKeys[key]) {
return;
}
this.renderedSceneKeys[key] = true;
scenes.push(this.renderScene(item, i));
});
return (
<View style={this.props.style}>
{scenes}
</View>
);
}

}

export default TabbedView;

0 comments on commit 156edac

Please sign in to comment.