web-dev-qa-db-fra.com

TabNavigator imbriqué dans StackNavigator: contrôle de l'en-tête

J'ai une configuration un peu comme ceci:

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

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

Le navigateur de pile a un en-tête, et c'est bien. Ce que je veux, c'est obtenir différentes icônes d'en-tête en fonction de l'onglet sur lequel je suis actuellement.

J'utilise les versions suivantes:

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

J'ai envisagé de changer ma configuration pour que chaque écran d'onglets ait sa propre StackNavigator, mais j'aime bien avoir l'animation glissante lorsque je change d'onglet et je ne veux pas que les icônes d'en-tête glissent. La barre d'en-tête doit rester statique mais afficher simplement des icônes différentes en fonction de l'onglet en cours.

6
Anthony De Smet

Vous pouvez utiliser comme ceci ci-dessous, https://reactnavigation.org/docs/fr/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(navigation.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"

}

//(navigation.state.routes[navigation.state.index])["routeName"aser //(navigation.state.routes Suivre 

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

Le code ci-dessus définira le titre dans l'en-tête de la pile racine où le TabBar réside en tant que première route. Nous définissons donc l'en-tête comme null pour la pile individuelle dans TabBar. En utilisant cette méthode, vous obtiendrez une animation tout en commutant les écrans dans TabBar puisque l’en-tête restera statique.

vous pouvez trouver la copie de travail ici https://www.dropbox.com/s/jca6ssn9zkzh9kn/Archive.zip?dl=0

Téléchargez ceci et exécutez ce qui suit.

  1. npm install // pour obtenir des dépendances 

  2. réactif-mise à niveau native // ​​pour obtenir le dossier Android et ios

  3. react-native link // pour lier des dépendances et des bibliothèques

  4. réactif natif run-ios (ou) réactif natif run-Android

    vous pouvez utiliser ce qui précède, laissez-moi savoir si.

6
dhivya s

Vous pouvez obtenir le comportement souhaité avec la configuration actuelle de la pile de navigation. Vous aurez peut-être besoin de changer plusieurs choses et de combiner plusieurs propriétés, mais c'est assez simple quand vous comprenez mieux.

J'essaie de l'expliquer avec un petit exemple.

Pensez à avoir ci-dessous des navigateurs;

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
})

Comme vous pouvez le constater, je configure le paramètre title à partir de l'état de navigation. Pour pouvoir définir les paramètres de ce navigateur, nous allons obtenir de l'aide de screenProps property;

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

J'ai créé un composant wrapper pour le navigateur de tabulation et transmis une fonction qui définit le paramètre title.

Pour la dernière partie, nous devons savoir comment et quand utiliser cette fonction que nous avons transmise. Pour cela, nous allons utiliser addListener navigation prop

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>
  }
}

Lorsque notre onglet est activé, la fonction transmise s’exécute puis définit le titre de cet onglet. Vous pouvez utiliser cette procédure pour définir différents boutons ou icônes pour l'en-tête. Vous pouvez trouver la collation de travail ici .

2
bennygenel

Dans AppNavigation.js // ou si vous avez défini vos itinéraires.

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.
  }
)

Dans Screen1.js

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

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

NOTE: Vous pouvez ajouter title, headersStyle, headerRight de la même manière, lisez ce lien en-tête de configuration pour plus de détails.

Dans Screen2.js faire similaire à Screen1

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

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

Header.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>
)

J'espère que cela vous aidera, si vous avez des doutes sur le code, n'hésitez pas à demander.

0
Rajat Gupta

Si vous utilisez la navigation réactive <2, c'est-à-dire ~ 1,5. * Vous pouvez le définir comme ceci.

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
})

Je ne suis pas sûr de savoir pourquoi ils ont supprimé cette fonctionnalité. Lorsque vous essayez la même chose, cela ne fonctionnera pas avec la dernière version de réaction-navigation Maintenant, la clé d'objet de titre est utilisée pour le repli semble-t-il.

Cela peut être utile à certains utilisateurs. Si vous le souhaitez, vous pouvez également essayer de déclasser. 

J'ai mis à niveau la navigation React pour mon projet, je pense que cette façon sera utile à quelqu'un

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
}
}
0
Ashwin Mothilal
const RootStack = createStackNavigator(
  {
    Home: {screen: HomeScreen},
    FilterScreen: createMaterialTopTabNavigator({
        Tab1: {screen:Tab1Screen},
        Tab2: {screen: Tab2Screen},
    }),
  },
  {
    mode: 'modal',
    headerMode: 'none',
  }
);


render() {
    return <RootStack/>;
}
0
Mahdi Bashirpour