登录逻辑处理
基本思路:分两个navigator,如果dva里面有token,则显示已正常的navigator,如果没有,则显示登录注册的navigator:
import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {navigationRef} from './RootNavigation';
import allScreens from './screens';
const StackNavigator = createStackNavigator();
const TabNavigator = createBottomTabNavigator();
export function getStackNavigator(initialRouteName) {
return (
<StackNavigator.Navigator
initialRouteName={initialRouteName}
>
{allScreens.map(({name, component, options}) => (
<StackNavigator.Screen
name={name}
key={name}
component={component}
options={options}
/>
))}
</StackNavigator.Navigator>
);
}
export function UnAuthRouter() {
return (
<NavigationContainer ref={navigationRef}>
{
getStackNavigator('Login')
}
</NavigationContainer>
);
}
export default function Router() {
const homeScreen = () => getStackNavigator('HomeScreen');
return (
<NavigationContainer ref={navigationRef}>
<TabNavigator.Navigator
screenOptions={({route}) => ({
tabBarIcon: ({focused, color, size}) => {
let iconName;
if (route.name === 'Home') {
iconName = focused ? 'ios-home' : 'ios-home-outline';
} else if (route.name === 'Matching') {
iconName = focused ? 'ios-heart-half' : 'ios-heart-half-outline';
} else if (route.name === 'Setting') {
iconName = focused ? 'ios-settings' : 'ios-settings-outline';
}
return <Ionicons name={iconName} size={size} color={color} />;
},
})}
tabBarOptions={{
activeTintColor: '#9605ff',
inactiveTintColor: 'gray',
keyboardHidesTabBar: true,
}}>
<TabNavigator.Screen name="Home" component={homeScreen} />
</TabNavigator.Navigator>
</NavigationContainer>
);
}
const App: () => React$Node = ({ token,dispatch }) => {
dispatch({type:'user/autoLogin'});
return (
<Provider>
<AppStateProvider>
{
token? <Router/> : <UnAuthRouter/>
}
</AppStateProvider>
</Provider>
);
}
配置返回按钮
{
name: 'BindPhone',
component: BindPhone,
options: {
headerShown: true,
headerBackTitle: '',
headerBackTitleVisible: false,
},
},
另外的属性headerBackImage
、headerLeft
配置rightButton:
React.useLayoutEffect(() => {
navigation.setOptions({
title: `Add ${title}`,
headerRight: () => (
<TouchableOpacity
style={styles.rightButton}
onPress={() => {
navigate('AddData', { ...params });
}}
>
<Text style={styles.btnTxt}>Add</Text>
</TouchableOpacity>
),
});
}, [navigation]);
获取传递参数
<TouchableOpacity
onPress={() => navigate('Statistical', { ...item })}
/>
接受参数
import { useRoute } from '@react-navigation/native';
const { params } = useRoute();
const { title } = params;
如果是4.x版本,则接收参数为:
const {
navigation: {
state: { params },
},
} = props;
封装全局导航
定义全局ref文件RootNavigation.js
:
import * as React from 'react';
export const navigationRef = React.createRef();
export function navigate(name, params) {
navigationRef.current?.navigate(name, params);
}
export function goBack() {
navigationRef.current?.goBack();
}
把ref
指定到根导航栈上面:
export function UnAuthRouter() {
return (
<NavigationContainer ref={navigationRef}>
{
getStackNavigator('Login')
}
</NavigationContainer>
);
}
把相应的方法指定到global变量上面:
/**
* @format
*/
import {AppRegistry} from 'react-native';
import {name as appName} from './app.json';
import dva from './src/dva';
import { navigato,isCN,showToast,successToast,failToast,loadingToast,hideToast,getWindow,goBack } from './src/utils';
global.navigate = navigato;
global.goBack = goBack;
global.getWindow = getWindow;
global.successToast = successToast;
global.failToast= failToast;
global.isCN = isCN;
global.loadingToast=loadingToast;
global.hideToast= hideToast;
global.showToast= showToast;
AppRegistry.registerComponent(appName, () => dva);
这样以后就可以全局任何地方使用navigate、goBack等方法了。
只有一级界面显示tabbar
function getStackNavigator({route, navigation},initialRouteName) {
try {
let tabBarVisible = true
if (route.state.index > 0 && route.name!='HomeScreen' && route.name!='MatchingScreen'&& route.name!='SettingScreen'){
tabBarVisible = false
}
navigation.setOptions({
tabBarVisible: tabBarVisible
})
} catch {
console.log("route state is undefined")
}
return (
<StackNavigator.Navigator initialRouteName={initialRouteName}
headerMode='none'
>
{
allScreens.map(({name,component,options})=>
<StackNavigator.Screen
key={Math.random()}
name={name}
component={component}
options={options}
/>)
}
</StackNavigator.Navigator>
)
}
自定义转场动画
function PrimaryNav() {
return (
<StackNavigator.Navigator
initialRouteName="Loading"
headerMode={'none'}
mode={'card'}
screenOptions={({ route }) => ({
headerTintColor: '#21c064',
headerTitleStyle: styles.headerTitleStyle,
cardStyleInterpolator: ({
closing,
current,
index,
insets,
inverted,
next,
layouts,
swiping,
current: { progress },
}) => {
const _index = index;
const width = layouts.screen.width;
const inputRange = [_index - 1, _index, _index + 1];
const outputRange = 1 ? [width, 0, -width * 0.3] : [-width, 0, width * -0.3];
const translateY = 0;
const translateX = progress.interpolate({
inputRange,
outputRange,
});
const opacity = progress.interpolate({
inputRange: [_index - 1, _index - 0.99, _index, _index + 0.99, _index + 1],
outputRange: [0, 1, 1, 0.85, 0],
});
return {
cardStyle: {
transform: [{ translateX }, { translateY }],
opacity,
},
overlayStyle: {
transform: [{ translateX }, { translateY }],
opacity,
},
};
},
})}
headerMode={'none'}
>
<StackNavigator.Screen name={'TabNavigator'} component={TabNavigator} />
<StackNavigator.Screen name={'TabNavigatorSalon'} component={TabNavigatorSalon} />
{allScreens.map(({ name, screen, navigationOptions }) => (
<StackNavigator.Screen
name={name}
key={name}
component={screen}
options={navigationOptions}
/>
))}
</StackNavigator.Navigator>
);
}
自定义tabbar
const Routes = [
{
iconSelected: require('../../assets/icons/noop.png'),
route: 'Home',
style: styles.noop,
},
{
iconSelected: require('../../assets/icons/calendar.png'),
route: 'Reservation',
style: styles.calendar,
},
{
iconSelected: require('../../assets/icons/person.png'),
route: 'Profile',
style: styles.profile,
},
];
function BottomTab({ state, descriptors, navigation, selectPage }) {
return (
<React.Fragment>
<View
style={{
height: isIphoneX ? 70 : 60,
width: SCREEN_WIDTH,
flexDirection: 'row',
position: 'absolute',
alignContent: 'center',
justifyContent: 'center',
bottom: 0,
backgroundColor: 'white',
shadowColor: 'rgba(0, 0, 0, 0.16)',
shadowOffset: {
width: 0,
height: 3,
},
shadowRadius: 6,
shadowOpacity: 1,
}}
>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const isFocused = state.index === index;
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
});
if (!isFocused && !event.defaultPrevented) {
selectPage(route.name);
navigation.navigate(route.name);
}
};
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
};
const item = Routes.find(item => item.route === route.name);
return (
<View key={index} style={styles.ButttonWrapper}>
<TouchableOpacity
key={`${index}`}
accessibilityRole="button"
accessibilityStates={isFocused ? ['selected'] : []}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID}
style={isFocused ? styles.inselected : styles.inselected}
// onPress={() => {
// this.handelNavigate(item.route);
// }}
onPress={onPress}
onLongPress={onLongPress}
>
<Image
resizeMode={'center'}
source={item.iconSelected}
style={[
item.style,
{
tintColor: isFocused ? AppStyles.color.blushPink : AppStyles.color.cloudyBlue,
},
]}
/>
<Text style={isFocused ? styles.selectedText : styles.unselectedText}>
{i18n.t(label)}
</Text>
</TouchableOpacity>
</View>
);
})}
</View>
</React.Fragment>
);
}
使用:
function TabNavigator(params) {
return (
<TabBar.Navigator tabBar={props => <BottomTab {...props} />}>
<TabBar.Screen name="Home" component={HomeScreen} />
<TabBar.Screen name="Reservation" component={ShowCategory} />
<TabBar.Screen name="Profile" component={ProfileScreen} />
</TabBar.Navigator>
);
}
设置透明背景以及去除阴影
headerStyle: {
backgroundColor: Colors.background,
elevation: 0, // remove shadow on Android
shadowOpacity: 0, // remove shadow on iOS
},
如果设置 headerTransparent: true,那header将不占空间,也就是下面view会上移,