Экран реакции-навигации, который скрывает TabBar от вложенного StackNavigator

Я новичок в react-navigation и пытаюсь оборачивать голову тем, как сделать следующее:

Учитывая эту навигационную структуру:

RootTabNavigator 

  LoggedOut_StackNavigator

    ...

  LoggedIn_StackNavigator

    LoggedIn_TabNavigator <-- TabBar rendered by this Navigator

      TabA_StackNavigator

        ScreenA
        ScreenB

Я хотел бы иметь возможность перемещаться от ScreenA до ScreenB, используя типичный переход "сползать вправо", таким образом, чтобы TabBar был показан на ScreenA, но не отображается на ScreenB. Другими словами, когда я перехожу к ScreenB, я хочу, чтобы он занял все окно.

Как только пользователь перейдет от ScreenA до ScreenB, он может либо нажать кнопку "Назад", чтобы вернуться к ScreenA, либо перейти к новым маршрутам, используя тот же переход с TabBar still not.

Что я пробовал:

  • navigationOptions.tabBarVisible: это свойство работает только при применении к TabA_StackNavigator, что означает, что все экранов в стеке также скрывают TabBar. Добавление его к экранам внутри StackNavigator не имеет эффекта.

  • Добавив новый AllScreens_StackNavigator в качестве брата из LoggedIn_TabNavigator и перейдя на маршруты внутри этого навигатора, я получаю сообщение об ошибке: Expect nav state to have routes and index, {"routeName":"ScreenB", "params": {}, "key": "init-id-1516..."}. Навигационное действие, которое я отправил, чтобы попытаться сделать это:

    {
      "action": Object {
        "params": Object {},
        "routeName": "ScreenB",
        "type": "Navigation/NAVIGATE",
      },
      "params": Object {},
      "routeName": "AllScreens_StackNavigator",
      "type": "Navigation/NAVIGATE",
    }
    

Любая помощь очень ценится!

Ответ 1

По-видимому, navigationOptions внутреннего компонента влияет также на родительский навигатор навигатора.

Решение

Это означает, что этот код должен работать для вас:

class ScreenB extends React.Component {
  static navigationOptions = {
    header: () => null,  //this will hide the Stack navigator header (TabA_StackNavigator)
    tabBarVisible: false //this will hide the TabBar navigator header (LoggedIn_TabNavigator)
  }

Описание

Во-первых, вы можете настроить параметры навигации на отдельный экран (компонент). Вы можете увидеть, как в фрагменте кода выше или здесь: React Navigation - Опции экранной навигации

Во-вторых, вы пытались:

Добавление его к экранам внутри StackNavigator не имеет эффекта.

Это не сработало, потому что для скрытия заголовка StackNavigator требуется установить для поля header значение null.

Из React Navigation:

React Element или функция, которая задает HeaderProps, возвращает React Элемент, отображаемый в виде заголовка. Настройка для null скрывает заголовок

В-третьих,, используя tabBarVisible, на самом деле правильно, но влияет только на TabNavigator. И чтобы он исчез только для одной вкладки, а не для всех вкладок, вам нужно установить ее на конкретном экране. ScreenB в вашем случае.

Надеюсь, это поможет!

Ответ 2

Следующее - это то, что в конечном итоге работает для меня, поэтому я отправляю ему надежды на то, что он помогает другим. У меня не было шанса попробовать реализацию @talzaj, поэтому я оставлю его другим, чтобы поддерживать все, что подходит для них. Следующее решение работает для меня хорошо, в том числе внутри вложенных навигаторов.

Я обновил свою навигационную структуру, чтобы:

  • LoggedIn_StackNavigator по-прежнему имеет LoggedIn_TabNavigator как один из его экранов, и этот LoggedIn_TabNavigator является начальным маршрутом LoggedIn_StackNavigator, как установлено с помощью initialRouteName.
  • LoggedIn_StackNavigator также содержит маршрут для каждого экрана, который когда-либо понадобится отобразить на весь экран и скрыть панель вкладок. (Если вы повторно используете экраны, где некоторые показаны с видимой полосой вкладок, а другие - там, где нет, обязательно используйте уникальные ключи для маршрутов, которые повторно используют один и тот же экран.

Структура навигации

Итак, структура навигации выглядит так:

RootTabNavigator 

  LoggedOut_StackNavigator

  LoggedIn_StackNavigator

    ScreenA // ( reuse screen component, different route key )

    ScreenB // ( reuse screen component, different route key )

    LoggedIn_TabNavigator <-- TabBar rendered by this Navigator

      TabA_StackNavigator

        ScreenA
        ScreenB

LoggedIn_StackNavigator:

И LoggedIn_StackNavigator выглядит следующим образом:

import { StackNavigator } from 'react-navigation';
import LoggedIn_TabNavigator from './LoggedIn_TabNavigator';
import { 
  ScreenA, 
  ScreenB, 
} from './LoggedIn_TabNavigator/TabA_StackNavigator/Screens';

const LoggedIn_StackNavigator = StackNavigator({
  WithoutTabBar_ScreenA: {
     screen: ScreenA
  },
  WithoutTabBar_ScreenB: {
    screen: ScreenB
  },
  LoggedIn_TabNavigator: {
    screen: LoggedIn_TabNavigator
  }
}, {
  initialRouteName: 'LoggedIn_TabNavigator'
});

export default LoggedIn_StackNavigator;

Оттуда я написал вспомогательную HOC для нажатия полноэкранных маршрутов:

import React from 'react';
import { withNavigation } from 'react-navigation';
import { fullScreenRoutePrefix } from './somewhere';

export default function withNavigateFullScreen(Child) {

  @withNavigation
  class WithNavigateFullScreenHOC extends React.Component {

    navigateToFullScreenRoute = (routeName, params) => {          
      this.props.navigation.navigate(
        `${fullScreenRoutePrefix}${routeName}`, params
      );
    }

    render() {
      return (
        <Child 
          {...this.props} 
          navigateFullScreen={this.navigateToFullScreenRoute} 
        />
      );
    }
  }
  return WithNavigateFullScreenHOC;
}

И затем я могу перейти к полноэкранным маршрутам следующим образом:

import React from 'react';
import { withNavigateFullScreen } from 'components/higher-order';
import { Text } from 'react-native';

@withNavigateFullScreen
export default class ScreenA extends React.Component {
  goToScreenB = () => {
    this.props.navigateFullScreen('ScreenB');
  }
  render() {
    return <Text onPress={this.goToScreenB}>Go To Screen B</Text>;
  }
}