やりたいこと
React Navigation で createBottomTabNavigatorを使って画面をタブ表示していて、かつタブ内に createStackNavigatorでスタックナビゲータを入れている時。
このスタックの最初のページ以外はタブバーを非表示にしたいということ、あると思います。
イメージでいうと、こんな感じです。
import {createStackNavigator, createBottomTabNavigator} from 'react-navigation'
const TabAStack =  createStackNavigator({
  ScreenA1,
  ScreenA2, //タブバー非表示にしたい
  ScreenA3, //タブバー非表示にしたい
});
export default createBottomTabNavigator({
  TabAStack,
  TabB,
  TabC
});
今回は、その方法を紹介します。
前提
React Navigationのバージョン
今回試したReact Navigationのバージョンは以下です。
"react-navigation": "^2.9.1"
実現方法
stackNavigatorのnavigationOptions で tabBarVisible を指定してあげるだけです。
「どの画面に対して」を指定する場合には、少なくとも以下の2通りがあります。
- スタックのindexで切り分ける場合
- 画面の名前で切り分ける場合
スタックのindexで切り分ける場合
navigation.state.indexでスタックの何番目を表示しているのか分かるので、スタックの一番最初(タブ内に最初に表示される画面)だけタブバーを表示したい場合は以下のようにします。
stackNavigator.navigationOptions = ({ navigation }) => ({
  //スタックの一番最初(ScreenA1)だけタブバーを表示する
  tabBarVisible: navigation.state.index === 0,
});
全体
import {createStackNavigator, createBottomTabNavigator} from 'react-navigation'
const TabAStack =  createStackNavigator({
  ScreenA1,
  ScreenA2, //タブバー非表示にしたい
  ScreenA3, //タブバー非表示にしたい
});
TabAStack.navigationOptions = ({ navigation }) => ({
  //スタックの一番最初だけタブバーを表示する
  tabBarVisible: navigation.state.index === 0,
});
export default createBottomTabNavigator({
  TabAStack,
  TabB,
  TabC
});
画面の名前で切り分ける場合
stackNavigator.navigationOptions = ({ navigation }) => ({
  const { index } = navigation.state;
  // または、 const index = navigation.state.index;
  const { routeName } = navigation.state.routes[index];
  // または、 const  routeName  = navigation.state.routes[index].routeName;
  //ScreenA1でのみタブバーを表示する
  tabBarVisible = routeName === ScreenA1
});
(余談)navigation.stateの中身
上記の navigation.stateですが、
ScreenA1=>ScreenA2=>ScreenA3
と遷移した時の中身は以下のようになっています。
indexで現在表示している画面のindexが分かり、また routesの配列にはスタックの履歴(ScreenA1, ScreenA2, ScreenA3)が入っています。
そのため、routes[index]で、現在の画面の情報を取得できます。
{
"key":"TabAStack",
"isTransitioning":false,
"index":2, //スタックの何番目か
"routes":[
    {
    "routeName":"ScreenA1", //ScreenA1の画面名
    "key":"id-1536728255349-2"
    },
    {
    "params":{}, //遷移時にパラメータを指定するとその情報がここに入ります。ヘッダーのタイトルとか。
    "routeName":"ScreenA2", //ScreenA2の画面名
    "key":"id-1536728255349-9"
    },
    {
    "routeName":"ScreenA3", //ScreenA3の画面名
    "key":"id-1536728255349-10"
    }
    ],
"routeName":"TabAStack"}
ちなみに、一個前の画面(ScreenA2)に戻るとこうなります。
{
"key":"TabAStack",
"isTransitioning":false,
"index":1, //スタックの何番目か
"routes":[
    {
    "routeName":"ScreenA1", //ScreenA1の画面名
    "key":"id-1536728255349-2"
    },
    {
    "params":{}, //遷移時にパラメータを指定するとその情報がここに入ります。ヘッダーのタイトルとか。
    "routeName":"ScreenA2", //ScreenA2の画面名
    "key":"id-1536728255349-9"
    },
    ],
"routeName":"TabAStack"}
ScreenA3が破棄されたので、 routesからその情報が消えました。
(余談)各画面のnavigationOptionsで指定することはできない
これまでの例では、stackNavigator全体のnavigationOptionsでタブバーの表示/非表示を切り替えていましたが、 以下のように、stackNavigator全体ではなく各画面のnavigationOptionsを指定する方法では上手く行きません。
const TabAStack =  createStackNavigator({
  ScreenA1: {
    screen: ScreenA1,
    navigationOptions: { tabBarVisible: true },
  },
    ScreenA2: {
    screen: ScreenA2,
    navigationOptions: { tabBarVisible: false },//タブバー非表示にしたい
  },
    ScreenA3: {
    screen: ScreenA3,
    navigationOptions: { tabBarVisible: false },//タブバー非表示にしたい
  },
});
なぜなら、この時のnavigationOptionsはTabAStackにしかかかっておらず、bottomNavigatorの方にはかかっていないためです。
また、以下も上手く行きませんでした。
const TabAStack =  createStackNavigator({
  ScreenA1,
  ScreenA2, //タブバー非表示にしたい
  ScreenA3, //タブバー非表示にしたい
},{
navigationOptions : ({ navigation }) => ({
  //スタックの一番最初だけタブバーを表示する
  tabBarVisible: navigation.state.index === 0,
});
});
そもそも、タブ毎にstackNavigatorに突っ込まない方が良いらしい
この記事を書いている途中で気が付いたのですが、
React Navigationのこの箇所に、以下のようにありました
Another option here would be to add another stack navigator as a parent of the tab navigator, and put the details screen there. This is recommended.
タブバーのなかにstackNavigatorをつっこむのではなく、tabNavigatorとそれ以外のタブバー要らない画面をstackNavigatorにつっこむと。
そして、  This is recommended. とあります。
import {createStackNavigator, createBottomTabNavigator} from 'react-navigation'
const TabNavigator = createBottomTabNavigator({
  ScreenA1,
  TabB,
  TabC
});
export default createStackNavigator({
  TabNavigator,
  ScreenA2, //タブナビゲータの外なのでタブバー表示されない
  ScreenA3, //同上
})
確かに、スッキリしますね。
ただ、TabBやTabCにも同じようにタブバー非表示の導線がある場合、この方法だとごっちゃになる気がしました。
const TabNavigator = createBottomTabNavigator({
  ScreenA1,
  ScreenB1,
  ScreenC1,
});
export default createStackNavigator({
  TabNavigator,
  ScreenA2, 
  ScreenA3, 
  ScreenB2, 
  ScreenB3,
  ScreenC2, 
  ScreenC3,
})
こういう構成のアプリはあまり無いのかもしれないですが、個人的には、それぞれstackNavigatorで囲ってあげる方が、「ScreenA2とScreenA3はScreenA1からしか遷移しない」など体的な導線が分かりやすいのかなぁと思いました。
参考URL
以下を参考にしました。