ZeroBased_IX
ZeroBased_IX

Reputation: 2727

Custom header in nested TabNavigator

I have a fairly complication navigation flow requirement for an app I'm working on.

I have a bottom tab bar, for each tab I'll be having a top tab bar for additional related views.

Which I have working, however on the videos tab in the nested "All" tab, I need to add a search bar to the header, and on the "Favourites" tab I'll be having yet another custom header with an "Edit" button at the top right.

How can I achieve this navigation whilst allowing React Navigation to co-ordinate everything. See images below:

What I don't want to do is disable the header at the MainNavigator level and enable it for particular routes. Or even worse embed the header and the tab bar on individual containers.

routes.js

import {
  StackNavigator,
  TabNavigator,
  DrawerNavigator
} from "react-navigation";
import Feed from "./containers/Feed";
import Auth from "./containers/Auth";
import News from "./containers/News";
import Videos from "./containers/Videos";
import FavouriteVideos from "./containers/FavouriteVideos";

const DashboardNavigator = TabNavigator(
  {
    Feed: {
      screen: Feed
    },
    News: {
      screen: News
    }
  },
  {
    tabBarPosition: "top"
  }
);

const VideoNavigator = TabNavigator(
  {
    Videos: {
      screen: Videos,
      navigationOptions: {
        title: "All"
      }
    },
    Favourites: {
      screen: FavouriteVideos
    }
  },
  {
    tabBarPosition: "top"
  }
);

const MainNavigator = TabNavigator(
  {
    Dashboard: {
      screen: DashboardNavigator,
      navigationOptions: ({}) => ({
        title: "Dashboard"
      })
    },
    Video: {
      screen: VideoNavigator,
      navigationOptions: ({}) => ({
        title: "Videos"
      })
    }
  },
  {
    swipeEnabled: false,
    animationEnabled: false,
    tabBarPosition: "bottom"
  }
);

const AuthenticatedNavigator = DrawerNavigator({
  App: {
    screen: MainNavigator
  }
});

const RootNavigator = StackNavigator({
  LoggedOut: {
    screen: Auth
  },
  Authenticated: {
    screen: AuthenticatedNavigator
  }
});

export default RootNavigator;

Snack

https://snack.expo.io/H1qeJrLiM

Images

Home

enter image description here

enter image description here

Upvotes: 0

Views: 3551

Answers (1)

bennygenel
bennygenel

Reputation: 24660

You can use react-navigation addListener function with combination setParams to achieve desired behavior.

You can listen for focus and blur events and then change a parameter. Then in your route config you can look for this parameter and decide what to render for header. I changed your snack to show a working example of what I am suggesting.

Example

const MainNavigator = TabNavigator(
  {
    Dashboard: {
      screen: DashboardNavigator,
      navigationOptions: ({}) => ({
        title: "Dashboard"
      })
    },
    Video: {
      screen: VideoNavigator,
      navigationOptions: ({navigation}) => {
        let title = 'Videos';
        navigation.state.routes.forEach((route) => {
          if(route.routeName === 'Videos' && route.params) {
            title = route.params.title;
          }
        });
        // I set title here but you can set a custom Header component
        return {
          tabBarLabel: 'Video',
          title
        }
      }
    }
  },
  {
    swipeEnabled: false,
    animationEnabled: false,
    tabBarPosition: "bottom"
  }
);

export default class Videos extends Component {
  constructor(props) {
    super(props);
    this.willFocusSubscription = props.navigation.addListener(
      'willFocus',
      payload => {
        this.props.navigation.setParams({title: 'All Videos'});
      }
    );
    this.willBlurSubscription = props.navigation.addListener(
      'willBlur',
      payload => {
        this.props.navigation.setParams({title: 'Just Videos'});
      }
    );
  }
  componentWillUnmount() {
     this.willFocusSubscription.remove();
     this.willBlurSubscription.remove();
  }
  render() {
    return (
      <View>
        <Text> Videos </Text>
      </View>
    );
  }
}

Upvotes: 1

Related Questions