如何在反应导航中使用用户指定的主题?
How to use user-specified theme in react-navigation?
我一直在尝试为我的 react-navigation 导航器设置主题,这很容易使用硬编码颜色,即 Colours.background
、Colours.accent
。
当用户通过身份验证时,我会提供他们的基本详细信息和主题对象。这使用 redux (state.auth.user.theme
)
存储在我的应用程序状态中
我有一个创建导航器的 AppNavigation。
AppNavigation.js
import React from 'react'
import { Text, Animated, Easing, Image, View } from 'react-native'
import { StackNavigator, DrawerNavigator, addNavigationHelpers } from 'react-navigation'
import Icon from 'react-native-vector-icons/EvilIcons'
import { connect } from 'react-redux'
import DrawerContainer from '../Containers/DrawerContainer'
import ScreenTwoScreen from '../Containers/ScreenTwoScreen'
import ScreenOneScreen from '../Containers/ScreenOneScreen'
import DashboardScreen from '../Containers/DashboardScreen'
import LoginScreen from '../Containers/LoginScreen'
import styles from './Styles/NavigationStyles'
import ThemeProvider from '../Themes/ThemeProvider';
import Images from '../Themes/Images';
const Colors = ThemeProvider()
const DrawerStack = DrawerNavigator({
screenOneScreen: { screen: ScreenOneScreen },
dashboardScreen: { screen: DashboardScreen },
}, {
gesturesEnabled: false,
contentComponent: DrawerContainer
})
const drawerButton = (navigation) =>
<Text
style={{ padding: 5, color: 'white' }}
onPress={() => {
// Coming soon: navigation.navigate('DrawerToggle')
// https://github.com/react-community/react-navigation/pull/2492
if (navigation.state.index === 0) {
navigation.navigate('DrawerOpen')
} else {
navigation.navigate('DrawerClose')
}
}
}><Icon name="navicon" color={Colors.headerText} size={24} /></Text>
// login stack
const LoginStack = StackNavigator({
loginScreen: { screen: LoginScreen },
}, {
headerMode: 'none',
navigationOptions: {
}
})
const logoStyle = {
height: 45,
width: 45,
marginLeft: 10,
resizeMode: 'contain'
}
const DrawerNavigation = StackNavigator({
DrawerStack: { screen: DrawerStack }
}, {
headerMode: 'float',
navigationOptions: ({ navigation }) => ({
headerStyle: { backgroundColor: Colors.brand },
title: 'Welcome!',
headerTintColor: Colors.headerText,
gesturesEnabled: false,
headerRight: drawerButton(navigation),
headerLeft: <Image source={Images.clubLogo} style={logoStyle} />
})
})
// Manifest of possible screens
const PrimaryNav = StackNavigator({
loginStack: { screen: LoginStack },
drawerStack: { screen: DrawerNavigation }
}, {
// Default config for all screens
headerMode: 'none',
initialRouteName: 'loginStack',
navigationOptions: {
headerStyle: styles.header
}
})
export default PrimaryNav
这在 ReduxNavigation.js 中使用:
ReduxNavigation.js
import React from 'react'
import * as ReactNavigation from 'react-navigation';
import { connect } from 'react-redux'
import AppNavigation from './AppNavigation'
import Colors from '../Themes/Colors'
import ThemeProvider from '../Themes/ThemeProvider'
// here is our redux-aware our smart component
class ReduxNavigation extends React.Component {
static navigationOptions = ({ navigation, screenProps }) => {
console.log(navigation)
return {
headerStyle: {
backgroundColor: this.props.user ? this.props.user.club.brand : Colors.brand
}
}
}
render() {
const { dispatch, nav, user } = this.props
const navigation = ReactNavigation.addNavigationHelpers({
dispatch,
state: nav
})
// if (user) {
// theme = ThemeProvider(user.club.theme)
// }
return <AppNavigation navigation={navigation} />
}
}
const mapStateToProps = state => ({ nav: state.nav, user: state.auth.user })
export default connect(mapStateToProps)(ReduxNavigation)
ThemeProvider.js
没什么特别的:
import Colors from './Colors';
const ThemeProvider = (other ={}) => {
return Object.assign({}, Colors, other)
}
export default ThemeProvider;
我尝试过的事情
- 创建了一个将用户主题合并到颜色中的主题提供程序方法,它有效但不正确。
- 将 AppNavigation 的核心移动到 ReduxNavigation 的渲染方法中,但这使应用程序无响应,这是可以理解的。
- 试图找出一种将主题作为道具传递给 PrimaryNav 的方法,反应导航不喜欢额外的道具。
想法和想法?此外,如果有任何用处,应用程序的核心是使用 InfiniteRed/ignite 生成的。
想出了一个办法,在 ReduxNavigation 中使用 screenProps
:
class ReduxNavigation extends React.Component {
render() {
const { dispatch, nav, user } = this.props
const navigation = ReactNavigation.addNavigationHelpers({
dispatch,
state: nav
})
return <AppNavigation navigation={navigation} screenProps={{ user }} />
}
}
然后在 AppNavigation 中我需要自定义主题的导航器中:
DrawerNavigation = StackNavigator({
DrawerStack: { screen: DrawerStack }
}, {
headerMode: 'float',
navigationOptions: ({ navigation, screenProps }) => {
let headerText = Colors.headerText;
let brand = Colors.brand;
let accent = Colors.accent;
if (screenProps.user) {
let theme = screenProps.user.club.theme;
brand = theme.brand;
headerText = theme.headerText;
accent = theme.accent;
}
return ({
headerStyle: { backgroundColor: brand },
title: 'Welcome!',
headerTintColor: headerText,
gesturesEnabled: false,
headerRight: drawerButton(navigation, headerText),
headerLeft: <Image source={Images.clubLogo} style={logoStyle} />
})
}
})
我一直在尝试为我的 react-navigation 导航器设置主题,这很容易使用硬编码颜色,即 Colours.background
、Colours.accent
。
当用户通过身份验证时,我会提供他们的基本详细信息和主题对象。这使用 redux (state.auth.user.theme
)
我有一个创建导航器的 AppNavigation。
AppNavigation.js
import React from 'react'
import { Text, Animated, Easing, Image, View } from 'react-native'
import { StackNavigator, DrawerNavigator, addNavigationHelpers } from 'react-navigation'
import Icon from 'react-native-vector-icons/EvilIcons'
import { connect } from 'react-redux'
import DrawerContainer from '../Containers/DrawerContainer'
import ScreenTwoScreen from '../Containers/ScreenTwoScreen'
import ScreenOneScreen from '../Containers/ScreenOneScreen'
import DashboardScreen from '../Containers/DashboardScreen'
import LoginScreen from '../Containers/LoginScreen'
import styles from './Styles/NavigationStyles'
import ThemeProvider from '../Themes/ThemeProvider';
import Images from '../Themes/Images';
const Colors = ThemeProvider()
const DrawerStack = DrawerNavigator({
screenOneScreen: { screen: ScreenOneScreen },
dashboardScreen: { screen: DashboardScreen },
}, {
gesturesEnabled: false,
contentComponent: DrawerContainer
})
const drawerButton = (navigation) =>
<Text
style={{ padding: 5, color: 'white' }}
onPress={() => {
// Coming soon: navigation.navigate('DrawerToggle')
// https://github.com/react-community/react-navigation/pull/2492
if (navigation.state.index === 0) {
navigation.navigate('DrawerOpen')
} else {
navigation.navigate('DrawerClose')
}
}
}><Icon name="navicon" color={Colors.headerText} size={24} /></Text>
// login stack
const LoginStack = StackNavigator({
loginScreen: { screen: LoginScreen },
}, {
headerMode: 'none',
navigationOptions: {
}
})
const logoStyle = {
height: 45,
width: 45,
marginLeft: 10,
resizeMode: 'contain'
}
const DrawerNavigation = StackNavigator({
DrawerStack: { screen: DrawerStack }
}, {
headerMode: 'float',
navigationOptions: ({ navigation }) => ({
headerStyle: { backgroundColor: Colors.brand },
title: 'Welcome!',
headerTintColor: Colors.headerText,
gesturesEnabled: false,
headerRight: drawerButton(navigation),
headerLeft: <Image source={Images.clubLogo} style={logoStyle} />
})
})
// Manifest of possible screens
const PrimaryNav = StackNavigator({
loginStack: { screen: LoginStack },
drawerStack: { screen: DrawerNavigation }
}, {
// Default config for all screens
headerMode: 'none',
initialRouteName: 'loginStack',
navigationOptions: {
headerStyle: styles.header
}
})
export default PrimaryNav
这在 ReduxNavigation.js 中使用:
ReduxNavigation.js
import React from 'react'
import * as ReactNavigation from 'react-navigation';
import { connect } from 'react-redux'
import AppNavigation from './AppNavigation'
import Colors from '../Themes/Colors'
import ThemeProvider from '../Themes/ThemeProvider'
// here is our redux-aware our smart component
class ReduxNavigation extends React.Component {
static navigationOptions = ({ navigation, screenProps }) => {
console.log(navigation)
return {
headerStyle: {
backgroundColor: this.props.user ? this.props.user.club.brand : Colors.brand
}
}
}
render() {
const { dispatch, nav, user } = this.props
const navigation = ReactNavigation.addNavigationHelpers({
dispatch,
state: nav
})
// if (user) {
// theme = ThemeProvider(user.club.theme)
// }
return <AppNavigation navigation={navigation} />
}
}
const mapStateToProps = state => ({ nav: state.nav, user: state.auth.user })
export default connect(mapStateToProps)(ReduxNavigation)
ThemeProvider.js
没什么特别的:
import Colors from './Colors';
const ThemeProvider = (other ={}) => {
return Object.assign({}, Colors, other)
}
export default ThemeProvider;
我尝试过的事情
- 创建了一个将用户主题合并到颜色中的主题提供程序方法,它有效但不正确。
- 将 AppNavigation 的核心移动到 ReduxNavigation 的渲染方法中,但这使应用程序无响应,这是可以理解的。
- 试图找出一种将主题作为道具传递给 PrimaryNav 的方法,反应导航不喜欢额外的道具。
想法和想法?此外,如果有任何用处,应用程序的核心是使用 InfiniteRed/ignite 生成的。
想出了一个办法,在 ReduxNavigation 中使用 screenProps
:
class ReduxNavigation extends React.Component {
render() {
const { dispatch, nav, user } = this.props
const navigation = ReactNavigation.addNavigationHelpers({
dispatch,
state: nav
})
return <AppNavigation navigation={navigation} screenProps={{ user }} />
}
}
然后在 AppNavigation 中我需要自定义主题的导航器中:
DrawerNavigation = StackNavigator({
DrawerStack: { screen: DrawerStack }
}, {
headerMode: 'float',
navigationOptions: ({ navigation, screenProps }) => {
let headerText = Colors.headerText;
let brand = Colors.brand;
let accent = Colors.accent;
if (screenProps.user) {
let theme = screenProps.user.club.theme;
brand = theme.brand;
headerText = theme.headerText;
accent = theme.accent;
}
return ({
headerStyle: { backgroundColor: brand },
title: 'Welcome!',
headerTintColor: headerText,
gesturesEnabled: false,
headerRight: drawerButton(navigation, headerText),
headerLeft: <Image source={Images.clubLogo} style={logoStyle} />
})
}
})