Вложенный TabNavigator внутри StackNavigator: управление заголовком

у меня есть такая настройка:

let Tabs = createBottomTabNavigator({
    screen1: Screen1,
    screen2: Screen2
})

let Stack = createStackNavigator({
    tabs: Tabs
    otherScreen: OtherScreen
})

навигатор стека имеет заголовок, и это нормально. Я хочу получить разные значки заголовков в зависимости от того, на какой вкладке я сейчас нахожусь.

Я использую следующие версии:

"react": "16.3.1",
"react-native": "~0.55.2",
"react-navigation": "^2.2.5"

я рассмотрел возможность переключения моей настройки так, чтобы каждый экран вкладки имел свой собственный StackNavigator но мне нравится иметь скользящую анимацию при переключении вкладок, и я не хочу, чтобы значки заголовков скользили. Заголовок должен оставайтесь статичными, но просто показывайте разные значки в зависимости от текущей вкладки.

5 ответов


можно использовать как это ниже https://reactnavigation.org/docs/en/stack-navigator.html

//Screen1 Stack.

const Screen1 = createStackNavigator ({
    Home: {
        screen: Home,
        navigationOptions: {
            header: null //Need to set header as null.
        }
    }
});

//Screen2 Stack

const Screen2 = createStackNavigator ({
    Profile: {
        screen: Profile,
        navigationOptions: {
            header: null  //Need to set header as null.
        }
    }
});


let Tabs = createMaterialTopTabNavigator({
    Screen1:{
      screen: Screen1 //Calling Screen1 Stack.
    },
    Screen2:{
      screen: Screen2 //Calling Screen2 Stack.
    }
},{ tabBarPosition: 'bottom' }) //this will set the TabBar at Bottom of your screen.

let Stack = createStackNavigator({
    tabs:{
      screen: Tabs, //You can add the NavigationOption here with navigation as parameter using destructuring.
      navigationOptions: ({navigation})=>{
       //title: (navigation.state.routes[navigation.state.index])["routeName"]  
       //this will fetch the routeName of Tabs in TabNavigation. If you set the routename of the TabNavigation as your Header. 

       //use the following title property,this will fetch the current stack's routeName which will be set as your header in the TabBar.

        //title: (navigation.state.routes[navigation.state.index]["routes"])[(navigation.state.routes[navigation.state.index]["index"])].routeName

       //you can use switch case,on matching the route name you can set title of the header that you want and also header left and right icons similarly.

        switch ((navigation.state.routes[navigation.state.index]["routes"])[(navigation.state.routes[navigation.state.index]["index"])].routeName) {
            case "Screen1":
                return {
                    title: "Home", 
                    headerLeft: (<Button
                        onPress={()=> alert("hi")}
                        title="Back"
                        color="#841584"
                        accessibilityLabel="Learn more about this purple button"
                    /> ),
                    headerRight: <Button title= "Right"/>
                }
            case "Screen2":
                return { 
                    title: "Profile",
                    headerLeft: (<Button
                        onPress={()=> alert("hi")}
                        title="Back"
                        color="#841584"
                        accessibilityLabel="Learn more about this purple button"
                    /> ),
                    headerRight: <Button title= "Right"/>
                }
            default:
                return { title: (navigation.state.routes[navigation.state.index]["routes"])[(navigation.state.routes[navigation.state.index]["index"])].routeName }
        }
      }
    },
    otherScreen:{
      screen: OtherScreen
    }
})

//navigationOptions

  navigationOptions: ({navigation})=>{
   //title: (navigation.state.routes[navigation.state.index])["routeName"]  
   //this will fetch the routeName of Tabs in TabNavigation. If you set the routename of the TabNavigation as your Header. 

   //use the following title property,this will fetch the current stack's routeName which will be set as your header in the TabBar.

    //title: (navigation.state.routes[navigation.state.index]["routes"])[(navigation.state.routes[navigation.state.index]["index"])].routeName

    switch ((navigation.state.routes[navigation.state.index]["routes"])[(navigation.state.routes[navigation.state.index]["index"])].routeName) {
        case "Screen1":
            return {
                title: "Home", 
                headerLeft: (<Button
                    onPress={()=> alert("hi")} //Here you can able to set the back behaviour.
                    title="Back"
                    color="#841584"
                    accessibilityLabel="Learn more about this purple button"
                /> ),
                headerRight: <Button title= "Right"/>
            }
        case "Screen2":
            return { 
                title: "Profile",
                headerLeft: (<Button
                    onPress={()=> alert("hi")} 
                    title="Back"
                    color="#841584"
                    accessibilityLabel="Learn more about this purple button"
                /> ),
                headerRight: <Button title= "Right"/>
            }
        default:
            return { title: (navigation.state.routes[navigation.state.index]["routes"])[(navigation.state.routes[navigation.state.index]["index"])].routeName }
    }
  }    

/ / alert (навигация.state)

{

    "routes":[
        {
            "key":"Screen1",
            "routeName":"Screen1",
            "routes":[
                {
                    "key":"Home",
                    "routeName":"Home",
                }
            ],
            "index":0,
            "isTransitioning":false,
            "key":"id-1530276062643-0"
        },
        {
            "key":"Screen2",
            "routeName":"Screen2",
            "routes":[
                {
                    "key":"Profile",
                    "routeName":"Profile",
                }
            ],
            "index":0,
            "isTransitioning":false,
            "key":"id-1530276062643-0"
        }
    ],
    "index":0,
    "isTransitioning":false,
    "routeName":"tabs",
    "key":"id-1530276062643-0"

}

//(навигация.государство.маршруты[навигация.государство.index]) ["routeName"] //(навигация.государство.маршруты[навигация.государство.индекс]["маршруты"])[(навигация.государство.маршруты[навигация.государство.index] ["index"])].routeName

this will give the current route name of the tab inside StackNavigation.

вышеуказанный код установит заголовок в заголовке корневого стека, где таббар находится как первый маршрут, поэтому мы устанавливаем заголовок как null для отдельного стека в таббаре. Используя этот способ, обеспечит анимацию при переключении экранов в TabBar, так как заголовок останется статическим.

вы можете найти рабочую копию здесь https://www.dropbox.com/s/jca6ssn9zkzh9kn/Archive.zip?dl=0

загрузите это и выполните следующее.

  1. установка npm //чтобы получить зависимости

  2. react-native upgrade / / чтобы получить папку android и ios

  3. react-native link / / для связывания зависимостей и библиотек

  4. реагировать-родной пробег-на iOS (или) реагируют-родной пробег-андроид

    вы можете использовать выше, Дайте мне знать, если любой.


вы можете достичь желаемого поведения с текущей конфигурацией стека навигации. Возможно, вам придется изменить пару вещей и объединить пару свойств, но это довольно просто, когда вы получаете голову вокруг него.

Я пытаюсь объяснить это небольшим примером.

рассмотрим наличие ниже навигаторов;

const Tabs = createBottomTabNavigator({
    screen1: Tab1,
    screen2: Tab2
})

const Stack = createStackNavigator({
    tabs: {
      screen: TabsPage,
      navigationOptions: ({navigation}) => {
        return { title: (navigation.state.params && navigation.state.params.title ? navigation.state.params.title : 'No Title' ) }
      }
    },
    otherScreen: Page
})

как вы можете видеть, я устанавливаю параметр заголовка из состояния навигации. Чтобы быть Элем, чтобы установить парам для этого навигатора, мы собираемся получить помощь от screenProps свойства;

class TabsPage extends Component {
  onTabsChange = (title) => {
    this.props.navigation.setParams({ title })
  }
  render() {
    return(<Tabs screenProps={{ onTabsChange: this.onTabsChange }} />)
  }
}

Я создал компонент-оболочку для TAB navigator и передал функцию, которая устанавливает параметр title.

для последней части нам нужно знать, как и когда использовать эту функцию, которую мы передали. Для этого мы будем использовать addListener навигация проп

class Tab1 extends React.Component {
  setTitle = () => {
    this.props.screenProps.onTabsChange('Title from Tab 1')
  }
  componentDidMount() {
    this.props.navigation.addListener('willFocus', this.setTitle)
  }
  render() {
    return <View><Text>{'Tab1'}</Text></View>
  }
}

когда наша вкладка сфокусирована, переданная функция будет запущена, а затем установите заголовок для этой вкладки. Вы можете используйте этот процесс для установки различных кнопок или значков для заголовка. Вы можете найти рабочую закуску здесь.


В AppNavigation.js / / или где вы определили свои маршруты.

let Tabs = createBottomTabNavigator({
    screen1: Screen1,
    screen2: Screen2
})

let Stack = createStackNavigator({
    tabs: Tabs
    otherScreen: OtherScreen
},{
    headerMode:"float", //Render a single header that stays at the top and animates as screens are changed. This is a common pattern on iOS.
    headerTransitionPreset:"fade-in-place" //this will give a slight transition when header icon change.
  }
)

В Screen1.js

class Screen1 extends Component {
 
 static navigationOptions = ({ navigation }) => {

    return {
      ...
      headerLeft: <HeaderLeftImage navigation={navigation} image={"Image_For_Screen1"}/>,
      ...
    }
  }
  ...
}

Примечание: Вы можете добавить название, headersStyle, headerRight таким же образом прочитать эту ссылку настройки заголовок для более подробной информации

В Screen2.на JS сделать похожими на Screen1

class Screen2 extends Component {
 
 static navigationOptions = ({ navigation }) => {

    return {
      ...
      headerLeft: <HeaderLeftImage navigation={navigation} image={"Image_For_Screen2"}/>,
      ...
    }
  }
  ...
}

заголовок.js

export const HeaderLeftImage = (props) => (
    <View style={{
       'add styles'
    }}>
        <TouchableOpacity onPress={() => {"Add action here" }}>
            <Image source={props.image} resizeMethod='resize' style={{ height: 30, width: 90, resizeMode: 'contain' }} />
        </TouchableOpacity>
    </View>
)

надеюсь, это поможет, если у вас есть какие-либо сомнения относительно кода, не стесняйтесь спрашивать.


const RootStack = createStackNavigator(
  {
    Home: {screen: HomeScreen},
    FilterScreen: createMaterialTopTabNavigator({
        Tab1: {screen:Tab1Screen},
        Tab2: {screen: Tab2Screen},
    }),
  },
  {
    mode: 'modal',
    headerMode: 'none',
  }
);


render() {
    return <RootStack/>;
}

Если вы используете навигацию react

const Tabs = TabNavigator({
    Tab1:{
         screen: Tab1,
         navigationOptions: ({navigation}) => {
            return { title: "Tab 1 Heading", tabBarLabel:"Tab 1 "}
    },
    }
    Tab2:{
       screen: Tab2
       navigationOptions: ({navigation}) => {
         return { title: "Tab 2 Heading", tabBarLabel:"Tab 2 "}
    }
    }
})

const Stack = StackNavigator({
    tabs: {
      screen: Tabs
      navigationOptions: ({navigation}) => {
        return { title: "Stack"}
      }
    },
    otherScreen: Page
})

Я не уверен, почему они удалили эту функцию, когда вы пытаетесь то же самое, это не будет работать на последней react-navigation. Теперь ключ объекта title используется для резервного копирования.

это может быть полезно некоторым пользователям. Если вы хотите, вы можете попробовать понизить также.

У меня есть обновленная навигация React для моего проекта, Я думаю, что этот способ будет полезен для кто-то!--3-->

const Tabs = TabNavigator({
     Tab1:{
        screen: Tab1,
        navigationOptions: ({navigation}) => {
           return { tabBarLabel:"Tab 1 "}
        }},
     Tab2:{
        screen: Tab2
        navigationOptions: ({navigation}) => {
           return { tabBarLabel:"Tab 2 "}
        }}
});
Tabs.navigationOptions = ({navigation})=>{
    const { routeName } = navigation.state.routes[navigation.state.index]; //This gives current route
    switch(routeName){
         case "Tab1":
           headerTitle="Tab 1";
           break;
         case "Tab1":
           headerTitle="Tab 1";
           break;
    }

 return {
   headerTitle: headerTitle
}
}