У меня такая установка:
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, но мне нравится скользящая анимация при переключении вкладок, и я не хочу, чтобы значки заголовков скользили вместе. Панель заголовка должна оставаться статичной, но просто отображать разные значки в зависимости от текущей вкладки.





Вы можете добиться желаемого поведения с помощью текущей конфигурации вашего стека навигации. Возможно, вам придется изменить пару вещей и объединить несколько свойств, но это довольно просто, если вы разберетесь с этим.
Я пытаюсь пояснить это на небольшом примере.
Подумайте о наличии навигаторов ниже;
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 }} />)
}
}
Я создал компонент-оболочку для навигатора вкладок и передал функцию, которая устанавливает параметр заголовка.
Для последней части нам нужно знать, как и когда использовать эту функцию, которую мы передали. Для этого мы будем использовать опору навигации 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>
}
}
Когда наша вкладка сфокусирована, переданная функция запустится, а затем установит заголовок для этой вкладки. Вы можете использовать этот процесс для настройки различных кнопок или значков для заголовка. Вы можете найти рабочую закуску здесь.
Вы можете проверить это Q stackoverflow.com/questions/56999290/… @bennygenel
Вы можете использовать это ниже, 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(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 provided)["routeName "] //(navigation.state.routes[navigation.state.index provided["routes" ])[(navigation.state.routes[navigation.state.indexicious["index" ])] ].routeName
this will give the current route name of the tab inside StackNavigation.
Приведенный выше код установит заголовок в заголовке корневого стека, где находится TabBar, в качестве первого маршрута, поэтому мы устанавливаем заголовок как null для отдельного стека в TabBar. Использование этого способа обеспечит анимацию при переключении экранов в TabBar, поскольку заголовок останется статическим.
Вы можете найти рабочую копию здесь https://www.dropbox.com/s/jca6ssn9zkzh9kn/Archive.zip?dl=0
Загрузите это и выполните следующее.
npm install //to get dependencies
react-native upgrade //to get android and ios folder
react-native link //to link dependencies and libraries
react-native run-ios (or) react-native run-android
вы можете использовать вышеуказанное, дайте мне знать, если таковые имеются.
@Anthony De Smet, я обновил свой ответ, пожалуйста, проверьте его и дайте мне знать, исправляет ли это ваше.
Хотя это работает, вы не можете изменить заголовок заголовка на что-либо иное, кроме routeName, не так ли? например Заголовок «Экран2» всегда будет «Экран2», или вы можете как-то установить его следующим образом: «Заголовок экрана для подпункта XXX»?
@Chris, я обновил свой ответ в соответствии с вашими требованиями. Вы можете добиться этого, используя переключатель case в navigationOptions, который соответствует нашему routeName, чтобы установить заголовок, headerLeft, headerRight и т. д. Таким образом мы можем установить заголовок независимо от routeName.
@dhivyas У меня также есть вопрос о вложенных вкладках прямо здесь stackoverflow.com/questions/55888800/…, как вы думаете, мы можем решить с помощью аналогичного решения?
Вы можете проверить это Q stackoverflow.com/questions/56999290/… @dhivyas
Как я могу это сделать с помощью react-navigation 5?
Здесь есть хороший пример в официальном документе: reactnavigation.org/docs/screen-options-resolution
В 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"}/>,
...
}
}
...
}ПРИМЕЧАНИЕ: Вы можете добавить title, headersStyle, headerRight таким же образом, прочтите эту ссылку конфигурация заголовка для более подробной информации.
В Screen2.js делаем аналогично 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>
)Надеюсь, это поможет, если у вас есть какие-либо сомнения относительно кода, не стесняйтесь спрашивать.
Вы можете проверить это Q stackoverflow.com/questions/56999290/… @RajatGupta
const RootStack = createStackNavigator(
{
Home: {screen: HomeScreen},
FilterScreen: createMaterialTopTabNavigator({
Tab1: {screen:Tab1Screen},
Tab2: {screen: Tab2Screen},
}),
},
{
mode: 'modal',
headerMode: 'none',
}
);
render() {
return <RootStack/>;
}
Вы можете проверить это Q stackoverflow.com/questions/56999290/… @MahdiBashirpour
Если вы используете React Navigation <2, то есть ~ 1.5. * Вы можете установить это так.
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 для своего проекта, думаю, этот способ будет кому-то полезен.
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
}
}
Вы можете проверить это Q stackoverflow.com/questions/56999290/… @AshwinMothilal
Вы можете просто использовать свойство headerShown: false. Я создал рабочий пример версии react-navigation: 5.x.x, вложив разные навигаторы: stack, drawer и bottom-tabs.
Вот ссылка на github:https://github.com/mvpbuddy/react-native-nested-navigators/
Для более подробного обзора вы можете проверить мой блог:https://mvpbuddy.io/blog/detail/how-to-build-an-app-with-nested-stack-drawer-bottom-tab-navigators
Это действительно лучшее решение, но как перейти к «otherScreen»? this.props.navigation.navigate ('Страница'); не работает из Tab1 или Tab2